namespace Automattic\WooCommerce\StoreApi\Routes\V1; use Automattic\WooCommerce\StoreApi\Routes\RouteInterface; use Automattic\WooCommerce\StoreApi\Exceptions\RouteException; use WP_REST_Request; use WP_REST_Response; /** * Batch Route class. */ class Batch extends AbstractRoute implements RouteInterface { /** * The route identifier. * * @var string */ const IDENTIFIER = 'batch'; /** * The schema item identifier. * * @var string */ const SCHEMA_TYPE = 'batch'; /** * Get the path of this REST route. * * @return string */ public function get_path() { return '/batch'; } /** * Get arguments for this REST route. * * @return array An array of endpoints. */ public function get_args() { return array( 'callback' => [ $this, 'get_response' ], 'methods' => 'POST', 'permission_callback' => '__return_true', 'args' => array( 'validation' => array( 'type' => 'string', 'enum' => array( 'require-all-validate', 'normal' ), 'default' => 'normal', ), 'requests' => array( 'required' => true, 'type' => 'array', 'maxItems' => 25, 'items' => array( 'type' => 'object', 'properties' => array( 'method' => array( 'type' => 'string', 'enum' => array( 'POST', 'PUT', 'PATCH', 'DELETE' ), 'default' => 'POST', ), 'path' => array( 'type' => 'string', 'required' => true, ), 'body' => array( 'type' => 'object', 'properties' => array(), 'additionalProperties' => true, ), 'headers' => array( 'type' => 'object', 'properties' => array(), 'additionalProperties' => array( 'type' => array( 'string', 'array' ), 'items' => array( 'type' => 'string', ), ), ), ), ), ), ), ); } /** * Get the route response. * * @see WP_REST_Server::serve_batch_request_v1 * https://developer.wordpress.org/reference/classes/wp_rest_server/serve_batch_request_v1/ * * @throws RouteException On error. * * @param WP_REST_Request $request Request object. * @return WP_REST_Response */ public function get_response( WP_REST_Request $request ) { try { foreach ( $request['requests'] as $args ) { if ( ! stristr( $args['path'], 'wc/store' ) ) { throw new RouteException( 'woocommerce_rest_invalid_path', __( 'Invalid path provided.', 'woocommerce' ), 400 ); } } $response = rest_get_server()->serve_batch_request_v1( $request ); } catch ( RouteException $error ) { $response = $this->get_route_error_response( $error->getErrorCode(), $error->getMessage(), $error->getCode(), $error->getAdditionalData() ); } catch ( \Exception $error ) { $response = $this->get_route_error_response( 'woocommerce_rest_unknown_server_error', $error->getMessage(), 500 ); } if ( is_wp_error( $response ) ) { $response = $this->error_to_response( $response ); } $nonce = wp_create_nonce( 'wc_store_api' ); $response->header( 'Nonce', $nonce ); $response->header( 'X-WC-Store-API-Nonce', $nonce ); $response->header( 'Nonce-Timestamp', time() ); $response->header( 'User-ID', get_current_user_id() ); return $response; } } namespace Automattic\WooCommerce\StoreApi\Routes\V1; use Automattic\WooCommerce\StoreApi\Exceptions\RouteException; /** * ProductCategoriesById class. */ class ProductCategoriesById extends AbstractRoute { /** * The route identifier. * * @var string */ const IDENTIFIER = 'product-categories-by-id'; /** * The routes schema. * * @var string */ const SCHEMA_TYPE = 'product-category'; /** * Get the path of this REST route. * * @return string */ public function get_path() { return '/products/categories/(?P[\d]+)'; } /** * Get method arguments for this REST route. * * @return array An array of endpoints. */ public function get_args() { return [ 'args' => array( 'id' => array( 'description' => __( 'Unique identifier for the resource.', 'woocommerce' ), 'type' => 'integer', ), ), [ 'methods' => \WP_REST_Server::READABLE, 'callback' => [ $this, 'get_response' ], 'permission_callback' => '__return_true', 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view', ) ), ), ], 'schema' => [ $this->schema, 'get_public_item_schema' ], ]; } /** * Get a single item. * * @throws RouteException On error. * @param \WP_REST_Request $request Request object. * @return \WP_REST_Response */ protected function get_route_response( \WP_REST_Request $request ) { $object = get_term( (int) $request['id'], 'product_cat' ); if ( ! $object || 0 === $object->id ) { throw new RouteException( 'woocommerce_rest_category_invalid_id', __( 'Invalid category ID.', 'woocommerce' ), 404 ); } $data = $this->prepare_item_for_response( $object, $request ); return rest_ensure_response( $data ); } } /** * Helper functions for interacting with the Store API. * * This file is autoloaded via composer.json. */ use Automattic\WooCommerce\StoreApi\StoreApi; use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema; if ( ! function_exists( 'woocommerce_store_api_register_endpoint_data' ) ) { /** * Register endpoint data under a specified namespace. * * @see Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema::register_endpoint_data() * * @param array $args Args to pass to register_endpoint_data. * @returns boolean|\WP_Error True on success, WP_Error on fail. */ function woocommerce_store_api_register_endpoint_data( $args ) { try { $extend = StoreApi::container()->get( ExtendSchema::class ); $extend->register_endpoint_data( $args ); } catch ( \Exception $error ) { return new \WP_Error( 'error', $error->getMessage() ); } return true; } } if ( ! function_exists( 'woocommerce_store_api_register_update_callback' ) ) { /** * Add callback functions that can be executed by the cart/extensions endpoint. * * @see Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema::register_update_callback() * * @param array $args Args to pass to register_update_callback. * @returns boolean|\WP_Error True on success, WP_Error on fail. */ function woocommerce_store_api_register_update_callback( $args ) { try { $extend = StoreApi::container()->get( ExtendSchema::class ); $extend->register_update_callback( $args ); } catch ( \Exception $error ) { return new \WP_Error( 'error', $error->getMessage() ); } return true; } } if ( ! function_exists( 'woocommerce_store_api_register_payment_requirements' ) ) { /** * Registers and validates payment requirements callbacks. * * @see Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema::register_payment_requirements() * * @param array $args Args to pass to register_payment_requirements. * @returns boolean|\WP_Error True on success, WP_Error on fail. */ function woocommerce_store_api_register_payment_requirements( $args ) { try { $extend = StoreApi::container()->get( ExtendSchema::class ); $extend->register_payment_requirements( $args ); } catch ( \Exception $error ) { return new \WP_Error( 'error', $error->getMessage() ); } return true; } } if ( ! function_exists( 'woocommerce_store_api_get_formatter' ) ) { /** * Returns a formatter instance. * * @see Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema::get_formatter() * * @param string $name Formatter name. * @return Automattic\WooCommerce\StoreApi\Formatters\FormatterInterface */ function woocommerce_store_api_get_formatter( $name ) { return StoreApi::container()->get( ExtendSchema::class )->get_formatter( $name ); } } if ( ! defined( 'ABSPATH' ) ) { die( '-1' ); } /*** WPBakery Page Builder Content elements refresh ***/ class VcSharedLibrary { // Here we will store plugin wise (shared) settings. Colors, Locations, Sizes, etc... /** * @var array */ private static $colors = array( 'Blue' => 'blue', 'Turquoise' => 'turquoise', 'Pink' => 'pink', 'Violet' => 'violet', 'Peacoc' => 'peacoc', 'Chino' => 'chino', 'Mulled Wine' => 'mulled_wine', 'Vista Blue' => 'vista_blue', 'Black' => 'black', 'Grey' => 'grey', 'Orange' => 'orange', 'Sky' => 'sky', 'Green' => 'green', 'Juicy pink' => 'juicy_pink', 'Sandy brown' => 'sandy_brown', 'Purple' => 'purple', 'White' => 'white', ); /** * @var array */ public static $icons = array( 'Glass' => 'glass', 'Music' => 'music', 'Search' => 'search', ); /** * @var array */ public static $sizes = array( 'Mini' => 'xs', 'Small' => 'sm', 'Normal' => 'md', 'Large' => 'lg', ); /** * @var array */ public static $button_styles = array( 'Rounded' => 'rounded', 'Square' => 'square', 'Round' => 'round', 'Outlined' => 'outlined', '3D' => '3d', 'Square Outlined' => 'square_outlined', ); /** * @var array */ public static $message_box_styles = array( 'Standard' => 'standard', 'Solid' => 'solid', 'Solid icon' => 'solid-icon', 'Outline' => 'outline', '3D' => '3d', ); /** * Toggle styles * @var array */ public static $toggle_styles = array( 'Default' => 'default', 'Simple' => 'simple', 'Round' => 'round', 'Round Outline' => 'round_outline', 'Rounded' => 'rounded', 'Rounded Outline' => 'rounded_outline', 'Square' => 'square', 'Square Outline' => 'square_outline', 'Arrow' => 'arrow', 'Text Only' => 'text_only', ); /** * Animation styles * @var array */ public static $animation_styles = array( 'Bounce' => 'easeOutBounce', 'Elastic' => 'easeOutElastic', 'Back' => 'easeOutBack', 'Cubic' => 'easeInOutCubic', 'Quint' => 'easeInOutQuint', 'Quart' => 'easeOutQuart', 'Quad' => 'easeInQuad', 'Sine' => 'easeOutSine', ); /** * @var array */ public static $cta_styles = array( 'Rounded' => 'rounded', 'Square' => 'square', 'Round' => 'round', 'Outlined' => 'outlined', 'Square Outlined' => 'square_outlined', ); /** * @var array */ public static $txt_align = array( 'Left' => 'left', 'Right' => 'right', 'Center' => 'center', 'Justify' => 'justify', ); /** * @var array */ public static $el_widths = array( '100%' => '', '90%' => '90', '80%' => '80', '70%' => '70', '60%' => '60', '50%' => '50', '40%' => '40', '30%' => '30', '20%' => '20', '10%' => '10', ); /** * @var array */ public static $sep_widths = array( '1px' => '', '2px' => '2', '3px' => '3', '4px' => '4', '5px' => '5', '6px' => '6', '7px' => '7', '8px' => '8', '9px' => '9', '10px' => '10', ); /** * @var array */ public static $sep_styles = array( 'Border' => '', 'Dashed' => 'dashed', 'Dotted' => 'dotted', 'Double' => 'double', 'Shadow' => 'shadow', ); /** * @var array */ public static $box_styles = array( 'Default' => '', 'Rounded' => 'vc_box_rounded', 'Border' => 'vc_box_border', 'Outline' => 'vc_box_outline', 'Shadow' => 'vc_box_shadow', 'Bordered shadow' => 'vc_box_shadow_border', '3D Shadow' => 'vc_box_shadow_3d', ); /** * Round box styles * * @var array */ public static $round_box_styles = array( 'Round' => 'vc_box_circle', 'Round Border' => 'vc_box_border_circle', 'Round Outline' => 'vc_box_outline_circle', 'Round Shadow' => 'vc_box_shadow_circle', 'Round Border Shadow' => 'vc_box_shadow_border_circle', ); /** * Circle box styles * * @var array */ public static $circle_box_styles = array( 'Circle' => 'vc_box_circle_2', 'Circle Border' => 'vc_box_border_circle_2', 'Circle Outline' => 'vc_box_outline_circle_2', 'Circle Shadow' => 'vc_box_shadow_circle_2', 'Circle Border Shadow' => 'vc_box_shadow_border_circle_2', ); /** * @return array */ public static function getColors() { return self::$colors; } /** * @return array */ public static function getIcons() { return self::$icons; } /** * @return array */ public static function getSizes() { return self::$sizes; } /** * @return array */ public static function getButtonStyles() { return self::$button_styles; } /** * @return array */ public static function getMessageBoxStyles() { return self::$message_box_styles; } /** * @return array */ public static function getToggleStyles() { return self::$toggle_styles; } /** * @return array */ public static function getAnimationStyles() { return self::$animation_styles; } /** * @return array */ public static function getCtaStyles() { return self::$cta_styles; } /** * @return array */ public static function getTextAlign() { return self::$txt_align; } /** * @return array */ public static function getBorderWidths() { return self::$sep_widths; } /** * @return array */ public static function getElementWidths() { return self::$el_widths; } /** * @return array */ public static function getSeparatorStyles() { return self::$sep_styles; } /** * Get list of box styles * * Possible $groups values: * - default * - round * - circle * * @param array $groups Array of groups to include. If not specified, return all * * @return array */ public static function getBoxStyles( $groups = array() ) { $list = array(); $groups = (array) $groups; if ( ! $groups || in_array( 'default', $groups, true ) ) { $list += self::$box_styles; } if ( ! $groups || in_array( 'round', $groups, true ) ) { $list += self::$round_box_styles; } if ( ! $groups || in_array( 'cirlce', $groups, true ) ) { $list += self::$circle_box_styles; } return $list; } /** * @return array */ public static function getColorsDashed() { $colors = array( esc_html__( 'Blue', 'js_composer' ) => 'blue', esc_html__( 'Turquoise', 'js_composer' ) => 'turquoise', esc_html__( 'Pink', 'js_composer' ) => 'pink', esc_html__( 'Violet', 'js_composer' ) => 'violet', esc_html__( 'Peacoc', 'js_composer' ) => 'peacoc', esc_html__( 'Chino', 'js_composer' ) => 'chino', esc_html__( 'Mulled Wine', 'js_composer' ) => 'mulled-wine', esc_html__( 'Vista Blue', 'js_composer' ) => 'vista-blue', esc_html__( 'Black', 'js_composer' ) => 'black', esc_html__( 'Grey', 'js_composer' ) => 'grey', esc_html__( 'Orange', 'js_composer' ) => 'orange', esc_html__( 'Sky', 'js_composer' ) => 'sky', esc_html__( 'Green', 'js_composer' ) => 'green', esc_html__( 'Juicy pink', 'js_composer' ) => 'juicy-pink', esc_html__( 'Sandy brown', 'js_composer' ) => 'sandy-brown', esc_html__( 'Purple', 'js_composer' ) => 'purple', esc_html__( 'White', 'js_composer' ) => 'white', ); return $colors; } } if ( ! defined( 'ABSPATH' ) ) { die( '-1' ); } /** * @since 4.4 vendors initialization moved to hooks in autoload/vendors. * * Used to initialize plugin yoast vendor. */ // 16 is required to be called after WPSEO_Admin_Init constructor. @since 4.9 add_action( 'plugins_loaded', 'vc_init_vendor_yoast', 16 ); function vc_init_vendor_yoast() { include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); // Require class-vc-wxr-parser-plugin.php to use is_plugin_active() below if ( is_plugin_active( 'wordpress-seo/wp-seo.php' ) || class_exists( 'WPSEO_Metabox' ) ) { require_once vc_path_dir( 'VENDORS_DIR', 'plugins/class-vc-vendor-yoast_seo.php' ); $vendor = new Vc_Vendor_YoastSeo(); if ( defined( 'WPSEO_VERSION' ) && version_compare( WPSEO_VERSION, '3.0.0' ) === - 1 ) { add_action( 'vc_after_set_mode', array( $vendor, 'load', ) ); } elseif ( is_admin() && 'vc_inline' === vc_action() ) { $vendor->frontendEditorBuild(); } } } if ( ! defined( 'ABSPATH' ) ) { die( '-1' ); } add_filter( 'attachment_fields_to_edit', 'vc_attachment_filter_field', 10, 2 ); add_filter( 'media_meta', 'vc_attachment_filter_media_meta', 10, 2 ); add_action( 'wp_ajax_vc_media_editor_add_image', 'vc_media_editor_add_image' ); add_action( 'wp_ajax_vc_media_editor_preview_image', 'vc_media_editor_preview_image' ); /** * @return array */ function vc_get_filters() { return array( 'antique' => esc_html__( 'Antique', 'js_composer' ), 'blackwhite' => esc_html__( 'Black & White', 'js_composer' ), 'boost' => esc_html__( 'Boost', 'js_composer' ), 'concentrate' => esc_html__( 'Concentrate', 'js_composer' ), 'country' => esc_html__( 'Country', 'js_composer' ), 'darken' => esc_html__( 'Darken', 'js_composer' ), 'dream' => esc_html__( 'Dream', 'js_composer' ), 'everglow' => esc_html__( 'Everglow', 'js_composer' ), 'forest' => esc_html__( 'Forest', 'js_composer' ), 'freshblue' => esc_html__( 'Fresh Blue', 'js_composer' ), 'frozen' => esc_html__( 'Frozen', 'js_composer' ), 'hermajesty' => esc_html__( 'Her Majesty', 'js_composer' ), 'light' => esc_html__( 'Light', 'js_composer' ), 'orangepeel' => esc_html__( 'Orange Peel', 'js_composer' ), 'rain' => esc_html__( 'Rain', 'js_composer' ), 'retro' => esc_html__( 'Retro', 'js_composer' ), 'sepia' => esc_html__( 'Sepia', 'js_composer' ), 'summer' => esc_html__( 'Summer', 'js_composer' ), 'tender' => esc_html__( 'Tender', 'js_composer' ), 'vintage' => esc_html__( 'Vintage', 'js_composer' ), 'washed' => esc_html__( 'Washed', 'js_composer' ), ); } /** * Add Image Filter field to media uploader * * @param array $form_fields , fields to include in attachment form * @param object $post , attachment record in database * * @return array $form_fields, modified form fields */ function vc_attachment_filter_field( $form_fields, $post ) { // don't add filter field, if image already has filter applied if ( get_post_meta( $post->ID, 'vc-applied-image-filter', true ) ) { return $form_fields; } $options = vc_get_filters(); $html_options = ''; foreach ( $options as $value => $title ) { $html_options .= ''; } $form_fields['vc-image-filter'] = array( 'label' => '', 'input' => 'html', 'html' => '
' . esc_html__( 'Image filter', 'js_composer' ) . '
', 'value' => get_post_meta( $post->ID, 'vc_image_filter', true ), 'helps' => '', ); return $form_fields; } /** * Apply filters to specified images * * If image(s) has filter specified via filters _POST param: * 1) copy it * 2) apply specified filter * 3) return new image id * * Required _POST params: * - array ids: array of attachment ids * * Optional _POST params: * - array filters: mapped array of ids and filters to apply * */ function vc_media_editor_add_image() { vc_user_access()->checkAdminNonce()->validateDie()->wpAny( 'upload_files' )->validateDie(); require_once vc_path_dir( 'HELPERS_DIR', 'class-vc-image-filter.php' ); $response = array( 'success' => true, 'data' => array( 'ids' => array(), ), ); $filters = (array) vc_post_param( 'filters', array() ); $ids = (array) vc_post_param( 'ids', array() ); if ( ! $ids ) { wp_send_json( $response ); } // default action is wp_handle_upload, which forces wp to check upload with is_uploaded_file() // override action to anything else to skip security checks $action = 'vc_handle_upload_imitation'; $file_key = 0; $post_id = 0; $post_data = array(); $overrides = array( 'action' => $action ); $_POST = array( 'action' => $action ); foreach ( $ids as $key => $attachment_id ) { if ( ! empty( $filters[ $attachment_id ] ) ) { $filter_name = $filters[ $attachment_id ]; } else { continue; } $source_path = get_attached_file( $attachment_id ); if ( empty( $source_path ) ) { continue; } $temp_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . basename( $source_path ); if ( ! copy( $source_path, $temp_path ) ) { continue; } $extension = strtolower( pathinfo( $temp_path, PATHINFO_EXTENSION ) ); $mime_type = ''; switch ( $extension ) { case 'jpeg': case 'jpg': $image = imagecreatefromjpeg( $temp_path ); $mime_type = 'image/jpeg'; break; case 'png': $image = imagecreatefrompng( $temp_path ); $mime_type = 'image/png'; break; case 'gif': $image = imagecreatefromgif( $temp_path ); $mime_type = 'image/gif'; break; default: $image = false; } if ( ! $image ) { continue; } $Filter = new vcImageFilter( $image ); $Filter->$filter_name(); if ( ! vc_save_gd_resource( $Filter->getImage(), $temp_path ) ) { continue; } $new_filename = basename( $temp_path, '.' . $extension ) . '-' . $filter_name . '.' . $extension; $_FILES = array( array( 'name' => $new_filename, 'type' => $mime_type, 'tmp_name' => $temp_path, 'error' => UPLOAD_ERR_OK, 'size' => filesize( $temp_path ), ), ); $new_attachment_id = media_handle_upload( $file_key, $post_id, $post_data, $overrides ); if ( ! $new_attachment_id || is_wp_error( $new_attachment_id ) ) { continue; } update_post_meta( $new_attachment_id, 'vc-applied-image-filter', $filter_name ); $ids[ $key ] = $new_attachment_id; } $response['data']['ids'] = $ids; wp_send_json( $response ); } /** * Generate filter preview * * Preview url is generated as data uri (base64) * * Required _POST params: * - string filter: filter name * - int attachment_id: attachment id * * @return void Results are sent out as json * @throws \Exception */ function vc_media_editor_preview_image() { vc_user_access()->checkAdminNonce()->validateDie()->wpAny( 'upload_files' )->validateDie(); require_once vc_path_dir( 'HELPERS_DIR', 'class-vc-image-filter.php' ); $response = array( 'success' => true, 'data' => array( 'src' => '', ), ); $filter_name = vc_post_param( 'filter', '' ); $attachment_id = vc_post_param( 'attachment_id', false ); $preferred_size = vc_post_param( 'preferred_size', 'medium' ); if ( ! $filter_name || ! $attachment_id ) { wp_send_json( $response ); } $attachment_path = get_attached_file( $attachment_id ); $attachment_details = wp_prepare_attachment_for_js( $attachment_id ); if ( ! isset( $attachment_details['sizes'][ $preferred_size ] ) ) { $preferred_size = 'thumbnail'; } $attachment_url = wp_get_attachment_image_src( $attachment_id, $preferred_size ); if ( empty( $attachment_path ) || empty( $attachment_url[0] ) ) { wp_send_json( $response ); } $source_path = dirname( $attachment_path ) . '/' . basename( $attachment_url[0] ); $image = vc_get_gd_resource( $source_path ); if ( ! $image ) { wp_send_json( $response ); } $Filter = new vcImageFilter( $image ); $Filter->$filter_name(); $extension = strtolower( pathinfo( $source_path, PATHINFO_EXTENSION ) ); ob_start(); switch ( $extension ) { case 'jpeg': case 'jpg': imagejpeg( $Filter->getImage() ); break; case 'png': imagepng( $Filter->getImage() ); break; case 'gif': imagegif( $Filter->getImage() ); break; } $data = ob_get_clean(); // @codingStandardsIgnoreLine $response['data']['src'] = 'data:image/' . $extension . ';base64,' . base64_encode( $data ); wp_send_json( $response ); } /** * Read file from disk as GD resource * * @param string $file * * @return bool|resource */ function vc_get_gd_resource( $file ) { $extension = strtolower( pathinfo( $file, PATHINFO_EXTENSION ) ); switch ( $extension ) { case 'jpeg': case 'jpg': return imagecreatefromjpeg( $file ); case 'png': return imagecreatefrompng( $file ); case 'gif': return imagecreatefromgif( $file ); } return false; } /** * Save GD resource to file * * @param resource $resource * @param string $file * * @return bool */ function vc_save_gd_resource( $resource, $file ) { $extension = strtolower( pathinfo( $file, PATHINFO_EXTENSION ) ); switch ( $extension ) { case 'jpeg': case 'jpg': return imagejpeg( $resource, $file ); case 'png': return imagepng( $resource, $file ); case 'gif': return imagegif( $resource, $file ); } return false; } /** * Add "Filter: ..." meta field to attachment details box * * @param array $media_meta , meta to include in attachment form * @param object $post , attachment record in database * * @return array|string */ function vc_attachment_filter_media_meta( $media_meta, $post ) { $filter_name = get_post_meta( $post->ID, 'vc-applied-image-filter', true ); if ( ! $filter_name ) { return $media_meta; } $filters = vc_get_filters(); if ( ! isset( $filters[ $filter_name ] ) ) { return $media_meta; } $media_meta .= esc_html__( 'Filter:', 'js_composer' ) . ' ' . $filters[ $filter_name ]; return $media_meta; } if ( ! defined( 'ABSPATH' ) ) { die( '-1' ); } function vc_navbar_undoredo() { if ( vc_is_frontend_editor() || is_admin() ) { require_once vc_path_dir( 'EDITORS_DIR', 'navbar/class-vc-navbar-undoredo.php' ); new Vc_Navbar_Undoredo(); } } add_action( 'admin_init', 'vc_navbar_undoredo' ); class MS_LMS_Email_Template_Helpers { public static function render( $template, $vars ) { $replacements = array(); foreach ( $vars as $key => $value ) { $replacements[ '{{' . $key . '}}' ] = $value; } return strtr( $template, $replacements ); } public static function link( $url ) { return sprintf( '%s', esc_url( $url ), esc_html( $url ) ); } } add_action( 'vc_after_init', 'stm_lms_ms_instructors_carousel_vc' ); function stm_lms_ms_instructors_carousel_vc() { $reviews = STM_LMS_Options::get_option( 'course_tab_reviews', true ); $sort_options = array( 'Default' => '' ); if ( $reviews ) { $sort_options['Rating'] = 'rating'; } vc_map( array( 'name' => esc_html__( 'STM LMS Instructors Carousel', 'masterstudy-lms-learning-management-system' ), 'base' => 'stm_lms_instructors_carousel', 'icon' => 'stm_lms_instructors_carousel', 'description' => esc_html__( 'Display Instructors in Styled Carousel', 'masterstudy-lms-learning-management-system' ), 'html_template' => STM_LMS_Templates::vc_locate_template( 'vc_templates/stm_lms_instructors_carousel' ), 'php_class_name' => 'WPBakeryShortCode_Stm_Lms_Ms_Instructors_Carousel', 'category' => array( esc_html__( 'Content', 'masterstudy-lms-learning-management-system' ), ), 'params' => array( array( 'type' => 'textfield', 'heading' => __( 'Title', 'masterstudy-lms-learning-management-system' ), 'param_name' => 'title', ), array( 'type' => 'textfield', 'heading' => __( 'Limit', 'masterstudy-lms-learning-management-system' ), 'param_name' => 'limit', 'std' => 10, ), array( 'type' => 'textfield', 'heading' => __( 'Per row', 'masterstudy-lms-learning-management-system' ), 'std' => 6, 'param_name' => 'per_row', ), array( 'type' => 'textfield', 'heading' => __( 'Per row on Notebook', 'masterstudy-lms-learning-management-system' ), 'std' => 4, 'param_name' => 'per_row_md', ), array( 'type' => 'textfield', 'heading' => __( 'Per row on Tablet', 'masterstudy-lms-learning-management-system' ), 'std' => 2, 'param_name' => 'per_row_sm', ), array( 'type' => 'textfield', 'heading' => __( 'Per row on Mobile', 'masterstudy-lms-learning-management-system' ), 'std' => 1, 'param_name' => 'per_row_xs', ), array( 'type' => 'colorpicker', 'heading' => __( 'Title color', 'masterstudy-lms-learning-management-system' ), 'param_name' => 'title_color', ), array( 'type' => 'dropdown', 'heading' => __( 'Style', 'masterstudy-lms-learning-management-system' ), 'param_name' => 'style', 'value' => array( 'Style 1' => 'style_1', 'Style 2' => 'style_2', ), 'std' => 'style_1', ), array( 'type' => 'dropdown', 'heading' => __( 'Sort By', 'masterstudy-lms-learning-management-system' ), 'param_name' => 'sort', 'value' => $sort_options, ), array( 'type' => 'dropdown', 'heading' => __( 'Prev/Next Buttons', 'masterstudy-lms-learning-management-system' ), 'param_name' => 'prev_next', 'value' => array( 'Enable' => 'enable', 'Disable' => 'disable', ), 'std' => 'enable', ), array( 'type' => 'dropdown', 'heading' => __( 'Pagination', 'masterstudy-lms-learning-management-system' ), 'param_name' => 'pagination', 'value' => array( 'Enable' => 'enable', 'Disable' => 'disable', ), 'std' => 'disable', ), array( 'type' => 'css_editor', 'heading' => esc_html__( 'Css', 'masterstudy-lms-learning-management-system' ), 'param_name' => 'css', 'group' => esc_html__( 'Design options', 'masterstudy-lms-learning-management-system' ), ), ), ) ); } if ( class_exists( 'WPBakeryShortCode' ) ) { class WPBakeryShortCode_Stm_Lms_Ms_Instructors_Carousel extends WPBakeryShortCode { } } .wp-block-uagb-testimonial.uagb-slick-carousel ul.slick-dots{margin-bottom:20px}.uagb-testimonial__wrap{box-sizing:border-box}.uagb-testimonial__wrap,.uagb-testimonial__wrap *{transition:all 0.2s}.uagb-icon-wrap .uagb-icon{display:inline-block}.uagb-tm__image-content img{height:auto !important}.uagb-tm__image,.uagb-testimonial__wrap,.uagb-tm__content,.uagb-tm__text-wrap{position:relative}.uagb-tm__imgicon-style-circle .uagb-tm__image img{border-radius:100%}.uagb-tm__imgicon-style-square .uagb-tm__image img{border-radius:0%}.uagb-tm__image img,.slick-slide .uagb-tm__image img{display:inline-block;box-sizing:content-box}.uagb-tm__content{overflow:hidden;text-align:center;word-break:break-word;border-radius:inherit;display:grid}.uagb-tm__image-position-left .uagb-tm__content,.uagb-tm__image-position-right .uagb-tm__content{display:flex}.uagb-tm__meta-inner{display:inline;width:100%;line-height:1}.uagb-tm__image-position-bottom .uagb-tm__image-content,.uagb-tm__image-position-bottom .uagb-testimonial-details{display:table-cell;vertical-align:middle}.uagb-tm__image-position-bottom .uagb-tm__image-content{padding-right:10px}.uagb-tm__author-name,.uagb-tm__company{display:block}.uagb-tm__image-aligned-middle .uagb-tm__image-content{align-self:center}.uagb-tm__author-name{font-size:30px;line-height:16px}.uagb-tm__company{font-size:15px;font-style:normal;line-height:16px;color:#888}.uagb-tm__overlay{height:100%;width:100%;top:0;left:0;position:absolute;background:transparent}.uagb-tm__items{visibility:hidden}.uagb-tm__items.slick-initialized{visibility:visible}.uagb-tm__image-position-top .uagb-tm__image-content{display:flex;justify-content:center}.uagb-slick-carousel.uagb-tm__arrow-outside .slick-next{right:-45px}.uagb-slick-carousel.uagb-tm__arrow-inside .slick-prev{left:25px;z-index:1}.uagb-slick-carousel.uagb-tm__arrow-inside .slick-next{right:25px}[dir="rtl"] .uagb-tm__arrow-inside.uagb-slick-carousel .slick-prev{left:auto;right:25px}[dir="rtl"] .uagb-tm__arrow-inside.uagb-slick-carousel .slick-next{left:25px;right:auto}[dir="rtl"] .uagb-tm__arrow-outside.uagb-slick-carousel .slick-prev{right:auto;left:-45px}[dir="rtl"] .uagb-tm__arrow-outside.uagb-slick-carousel .slick-next{left:auto;right:-45px}@media (min-width: 1025px){.wp-block-uagb-testimonial.uagb-post__carousel_notset .slick-slide:last-child .uagb-testimonial__wrap{padding-right:0}.wp-block-uagb-testimonial.uagb-post__carousel_notset .slick-slide:first-child .uagb-testimonial__wrap{padding-left:0}.wp-block-uagb-testimonial.uagb-post__carousel_notset .uagb-testimonial__wrap{margin-bottom:0}}@media (max-width: 976px){.wp-block-uagb-testimonial.uagb-post__carousel_notset-tablet .uagb-testimonial__wrap{margin-bottom:0}.wp-block-uagb-testimonial.uagb-post__carousel_notset-tablet .slick-slide:last-child .uagb-testimonial__wrap{padding-right:0}.wp-block-uagb-testimonial.uagb-post__carousel_notset-tablet .slick-slide:first-child .uagb-testimonial__wrap{padding-left:0}.uagb-tm-stacked-tablet.uagb-tm__image-position-bottom .uagb-tm__image-content,.uagb-tm-stacked-tablet.uagb-tm__image-position-bottom .uagb-testimonial-details{display:block;vertical-align:middle}.uagb-tm-stacked-tablet.uagb-tm__image-position-left .uagb-tm__content,.uagb-tm-stacked-tablet.uagb-tm__image-position-right .uagb-tm__content{display:block}.uagb-tm-stacked-tablet.uagb-tm__image-position-right.uagb-tm-reverse-order-tablet .uagb-tm__content{display:inline-flex;flex-direction:column-reverse}.uagb-tm-stacked-tablet.uagb-tm__image-aligned-top .uagb-tm__image-content{display:inline-flex;align-self:center}.uagb-slick-carousel.uagb-tm__arrow-outside .slick-prev{left:-10px;z-index:1}.uagb-slick-carousel.uagb-tm__arrow-outside .slick-next{right:-10px}[dir="rtl"] .uagb-slick-carousel.uagb-tm__arrow-outside .slick-prev{left:auto;right:15px}[dir="rtl"] .uagb-slick-carousel.uagb-tm__arrow-outside .slick-next{left:15px;right:auto}}@media (max-width: 768px){.wp-block-uagb-testimonial.uagb-post__carousel_notset-mobile .uagb-testimonial__wrap{margin-bottom:0}.wp-block-uagb-testimonial.uagb-post__carousel_notset-mobile .slick-slide:last-child .uagb-testimonial__wrap{padding-right:0}.wp-block-uagb-testimonial.uagb-post__carousel_notset-mobile .slick-slide:first-child .uagb-testimonial__wrap{padding-left:0}.uagb-tm-stacked-mobile.uagb-tm__image-position-bottom .uagb-tm__image-content,.uagb-tm-stacked-mobile.uagb-tm__image-position-bottom .uagb-testimonial-details{display:block;vertical-align:middle}.uagb-tm-stacked-mobile.uagb-tm__image-position-left .uagb-tm__content,.uagb-tm-stacked-mobile.uagb-tm__image-position-right .uagb-tm__content{display:block}.uagb-tm-stacked-mobile.uagb-tm__image-position-right.uagb-tm-reverse-order-mobile .uagb-tm__content{display:inline-flex;flex-direction:column-reverse}.uagb-tm-stacked-mobile.uagb-tm__image-aligned-top .uagb-tm__image-content{display:inline-flex;align-self:center}}.entry-content .wp-block-uagb-testimonial .is-carousel ul.slick-dots{padding:unset} class PMPro_Email_Template_Admin_Change extends PMPro_Email_Template { /** * The user object of the user to send the email to. * * @var WP_User */ protected $user; /** * Constructor. * * @since 3.4 * * @param WP_User $user The user object of the user to send the email to. */ public function __construct( WP_User $user ) { $this->user = $user; } /** * Get the email template slug. * * @since 3.4 * * @return string The email template slug. */ public static function get_template_slug() { return 'admin_change'; } /** * Get the "nice name" of the email template. * * @since 3.4 * * @return string The "nice name" of the email template. */ public static function get_template_name() { return esc_html__( 'Admin Change', 'paid-memberships-pro' ); } /** * Get "help text" to display to the admin when editing the email template. * * @since 3.4 * * @return string The "help text" to display to the admin when editing the email template. */ public static function get_template_description() { return esc_html__( 'The site administrator can manually update a user\'s membership through the WordPress admin. This email notifies the member of the level update.', 'paid-memberships-pro' ); } /** * Get the default subject for the email. * * @since 3.4 * * @return string The default subject for the email. */ public static function get_default_subject() { return esc_html__( "Your membership at !!sitename!! has been changed", "paid-memberships-pro" ); } /** * Get the default body content for the email. * * @since 3.4 * * @return string The default body content for the email. */ public static function get_default_body() { return wp_kses_post( __( '

An administrator at !!sitename!! has changed your membership level.

!!membership_change!!

If you did not request this membership change and would like more information please contact us at !!siteemail!!

Log in to your membership account here: !!login_url!!

', 'paid-memberships-pro' ) ); } /** * Get the email template variables for the email. * * @since 3.4 * * @return array The email template variables for the email (key => value pairs). */ public function get_email_template_variables() { $user = $this->user; // If the user no longer has a membership level, set the membership_change text to "Membership has been cancelled." if ( ! pmpro_hasMembershipLevel( null, $this->user->ID ) ) { $membership_change = esc_html__( 'Your membership has been cancelled.', 'paid-memberships-pro' ); } else { $membership_change = esc_html__( 'You can view your current memberships by logging in and visiting your membership account page.', 'paid-memberships-pro' ); } $email_template_variables = array( 'membership_change' => $membership_change, 'subject' => $this->get_default_subject(), 'name' => $user->display_name, 'display_name' => $user->display_name, 'user_login' => $user->user_login, 'user_email' => $user->user_email, ); return $email_template_variables; } /** * Get the email template variables for the email paired with a description of the variable. * * @since 3.4 * * @return array The email template variables for the email (key => value pairs). */ public static function get_email_template_variables_with_description() { return array( '!!display_name!!' => esc_html__( 'The display name of the user.', 'paid-memberships-pro' ), '!!user_login!!' => esc_html__( 'The username of the user.', 'paid-memberships-pro' ), '!!user_email!!' => esc_html__( 'The email address of the user.', 'paid-memberships-pro' ), '!!membership_change!!' => esc_html__( 'A message indicating the change in membership.', 'paid-memberships-pro' ), ); } /** * Get the email address to send the email to. * * @since 3.4 * * @return string The email address to send the email to. */ public function get_recipient_email() { return $this->user->user_email; } /** * Get the name of the email recipient. * * @since 3.4 * * @return string The name of the email recipient. */ public function get_recipient_name() { return $this->user->display_name; } /** * Returns the arguments to send the test email from the abstract class. * * @since 3.5 * * @return array The arguments to send the test email from the abstract class. */ public static function get_test_email_constructor_args() { global $current_user; return array( $current_user ); } } /** * Register the email template. * * @since 3.4 * * @param array $email_templates The email templates (template slug => email template class name) * @return array The modified email templates array. */ function pmpro_email_templates_change( $email_templates ) { $email_templates['admin_change'] = 'PMPro_Email_Template_Admin_Change'; return $email_templates; } add_filter( 'pmpro_email_templates', 'pmpro_email_templates_change' ); (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-453a8273"],{"0032":function(e,a,l){"use strict";var t=function(){var e=this,a=e.$createElement,l=e._self._c||a;return l("svg",{class:["idx-wp-icon","idx-wp-icon-"+e.icon,{"idx-wp-icon-spin":e.spin}],attrs:{role:"image","aria-hidden":"true",focusable:"false"}},[l("use",{attrs:{"xlink:href":"#"+e.icon}})])},n=[],i={name:"SvgIcon",props:{icon:{type:String,required:!0},spin:{type:Boolean,default:!1}}},r=i,o=(l("a4aa"),l("2877")),u=Object(o["a"])(r,t,n,!1,null,null,null);a["a"]=u.exports},"0633":function(e,a,l){"use strict";var t=function(){var e=this,a=e.$createElement,l=e._self._c||a;return l("idx-block",{attrs:{tag:"fieldset",className:{"form-content":!0,"form-content--disabled":e.formDisabled}}},[l("idx-block",{attrs:{className:"form-content__header"}},[l("idx-block",{attrs:{tag:"h2",className:"form-content__title"}},[e._v("Default State")]),l("p",[e._v(" You can enter a default state that will automatically be output on template pages and widgets that show the state. When you create a listing and leave the state field empty, the default below will be shown. You can override the default on each listing by entering a value into the state field. ")])],1),l("idx-form-group",[l("idx-form-label",{attrs:{customClass:"form-content__label",target:e.$idxStrap.prefix+"default-state"}},[e._v("Choose Default State")]),l("idx-form-input",{attrs:{type:"text",disabled:e.formDisabled,id:e.$idxStrap.prefix+"default-state",placeholder:"Enter your default state",value:e.defaultState},on:{change:function(a){return e.$emit("form-field-update",{key:"defaultState",value:a.target.value})}}})],1),l("idx-block",{attrs:{className:"form-content__header"}},[l("idx-block",{attrs:{tag:"h2",className:"form-content__title"}},[e._v("Default Currency")]),l("p",[e._v("Select a default currency symbol and optional currency code to display on listings.")])],1),l("idx-form-group",[l("idx-form-label",{attrs:{customClass:"form-content__label"}},[e._v("Currency Symbol")]),l("idx-custom-select",{attrs:{ariaLabel:"Currency Symbol",placeholder:"None",disabled:e.formDisabled,selected:e.currencySymbolSelected,options:e.currency.currencySymbols},on:{"selected-item":function(a){return e.$emit("form-field-update",{key:"currencySymbolSelected",value:a.value})}}})],1),l("idx-form-group",[l("idx-form-label",{attrs:{customClass:"form-content__label"}},[e._v("Currency Code")]),l("idx-custom-select",{attrs:{ariaLabel:"Currency Code",placeholder:"None",disabled:e.formDisabled,selected:e.currencyCodeSelected,options:e.currency.currencyCodes},on:{"selected-item":function(a){return e.$emit("form-field-update",{key:"currencyCodeSelected",value:a.value})}}})],1),l("idx-form-group",{attrs:{customClass:"form-content__toggle"}},[e._v(" Display Currency Code on Listings "),l("idx-toggle-slider",{attrs:{label:"Display Currency Code on Listings",uncheckedState:"No",checkedState:"Yes",active:e.displayCurrencyCode,disabled:e.formDisabled},on:{toggle:function(a){return e.$emit("form-field-update",{key:"displayCurrencyCode",value:!e.displayCurrencyCode})}}})],1),l("idx-block",{attrs:{className:"form-content__header"}},[l("idx-block",{attrs:{tag:"h2",className:"form-content__title"}},[e._v("Default Number of Posts")]),l("p",[e._v(" The default number of posts displayed on a listing archive page is 9. Here you can set a custom number. Enter -1 to display all listing posts. "),l("i",[e._v("If you have more than 20-30 posts, it's not recommended to show all or your page will load slow.")])])],1),l("idx-form-group",[l("idx-form-label",{attrs:{customClass:"form-content__label",target:e.$idxStrap.prefix+"default-posts"}},[e._v("Number of Posts on Listing Archive Page")]),l("idx-form-input",{attrs:{type:"text",disabled:e.formDisabled,id:e.$idxStrap.prefix+"default-posts",value:e.numberOfPosts},on:{change:function(a){return e.$emit("form-field-update",{key:"numberOfPosts",value:a.target.value})}}})],1),l("idx-block",{attrs:{className:"form-content__header"}},[l("idx-block",{attrs:{tag:"h2",className:"form-content__title"}},[e._v("Default Disclaimer")]),l("p",[e._v("Optionally enter a disclaimer to show on single listings. This can be overridden on individual listings.")])],1),l("idx-form-group",[l("idx-form-label",{attrs:{customClass:"form-content__label",target:e.$idxStrap.prefix+"default-disclaimer"}},[e._v("Default Disclaimer")]),l("idx-textarea",{attrs:{type:"text",disabled:e.formDisabled,id:e.$idxStrap.prefix+"default-disclaimer",placeholder:"Disclaimer text",rows:"3",value:e.defaultDisclaimer},on:{change:function(a){return e.$emit("form-field-update",{key:"defaultDisclaimer",value:a.target.value})}}})],1),l("idx-block",{attrs:{className:"form-content__header"}},[l("idx-block",{attrs:{tag:"h2",className:"form-content__title"}},[e._v("Listings Slug")]),l("p",[e._v(" Optionally change the slug of the listing post type. Don't forget to "),l("a",{attrs:{href:"../wp-admin/options-permalink.php",target:"_blank"}},[e._v(" reset your permalinks ")]),e._v(" if you change the slug! ")])],1),l("idx-form-group",[l("idx-form-label",{attrs:{customClass:"form-content__label",target:e.$idxStrap.prefix+"listings-slug"}},[e._v("Listings Slug")]),l("idx-form-input",{attrs:{type:"text",disabled:e.formDisabled,id:e.$idxStrap.prefix+"listings-slug",value:e.listingSlug},on:{change:function(a){return e.$emit("form-field-update",{key:"listingSlug",value:a.target.value})}}})],1)],1)},n=[],i=(l("a9e3"),[{value:"none",label:"None"},{value:"USD",label:"United States dollar"},{value:"GBP",label:"British pound"},{value:"CAD",label:"Canadian dollar"},{value:"EUR",label:"Euro"},{value:"MXN",label:"Mexican peso"},{value:"---",label:"---"},{value:"AED",label:"United Arab Emirates dirham"},{value:"AFN",label:"Afghan afghani"},{value:"ALL",label:"Albanian lek"},{value:"AMD",label:"Armenian dram"},{value:"AOA",label:"Angolan kwanza"},{value:"ARS",label:"Argentine peso"},{value:"AUD",label:"Australian dollar"},{value:"AWG",label:"Aruban florin"},{value:"AZN",label:"Azerbaijani manat"},{value:"BAM",label:"Bosnia and Herzegovina convertible mark"},{value:"BBD",label:"Barbadian dollar"},{value:"BDT",label:"Bangladeshi taka"},{value:"BGN",label:"Bulgarian lev"},{value:"BHD",label:"Bahraini dinar"},{value:"BIF",label:"Burundian franc"},{value:"BMD",label:"Bermudian dollar"},{value:"BND",label:"Brunei dollar"},{value:"BOB",label:"Bolivian boliviano"},{value:"BRL",label:"Brazilian real"},{value:"BSD",label:"Bahamian dollar"},{value:"BTN",label:"Bhutanese ngultrum"},{value:"BWP",label:"Botswana pula"},{value:"BYR",label:"Belarusian ruble"},{value:"BZD",label:"Belize dollar"},{value:"CDF",label:"Congolese franc"},{value:"CHF",label:"Swiss franc"},{value:"CLP",label:"Chilean peso"},{value:"CNY",label:"Chinese yuan"},{value:"COP",label:"Colombian peso"},{value:"CRC",label:"Costa Rican colón"},{value:"CUP",label:"Cuban convertible peso"},{value:"CVE",label:"Cape Verdean escudo"},{value:"CZK",label:"Czech koruna"},{value:"DJF",label:"Djiboutian franc"},{value:"DKK",label:"Danish krone"},{value:"DOP",label:"Dominican peso"},{value:"DZD",label:"Algerian dinar"},{value:"EGP",label:"Egyptian pound"},{value:"ERN",label:"Eritrean nakfa"},{value:"ETB",label:"Ethiopian birr"},{value:"FJD",label:"Fijian dollar"},{value:"FKP",label:"Falkland Islands pound"},{value:"GEL",label:"Georgian lari"},{value:"GHS",label:"Ghana cedi"},{value:"GMD",label:"Gambian dalasi"},{value:"GNF",label:"Guinean franc"},{value:"GTQ",label:"Guatemalan quetzal"},{value:"GYD",label:"Guyanese dollar"},{value:"HKD",label:"Hong Kong dollar"},{value:"HNL",label:"Honduran lempira"},{value:"HRK",label:"Croatian kuna"},{value:"HTG",label:"Haitian gourde"},{value:"HUF",label:"Hungarian forint"},{value:"IDR",label:"Indonesian rupiah"},{value:"ILS",label:"Israeli new shekel"},{value:"IMP",label:"Manx pound"},{value:"INR",label:"Indian rupee"},{value:"IQD",label:"Iraqi dinar"},{value:"IRR",label:"Iranian rial"},{value:"ISK",label:"Icelandic króna"},{value:"JEP",label:"Jersey pound"},{value:"JMD",label:"Jamaican dollar"},{value:"JOD",label:"Jordanian dinar"},{value:"JPY",label:"Japanese yen"},{value:"KES",label:"Kenyan shilling"},{value:"KGS",label:"Kyrgyzstani som"},{value:"KHR",label:"Cambodian riel"},{value:"KMF",label:"Comorian franc"},{value:"KPW",label:"North Korean won"},{value:"KRW",label:"South Korean won"},{value:"KWD",label:"Kuwaiti dinar"},{value:"KYD",label:"Cayman Islands dollar"},{value:"KZT",label:"Kazakhstani tenge"},{value:"LAK",label:"Lao kip"},{value:"LBP",label:"Lebanese pound"},{value:"LKR",label:"Sri Lankan rupee"},{value:"LRD",label:"Liberian dollar"},{value:"LSL",label:"Lesotho loti"},{value:"LTL",label:"Lithuanian litas"},{value:"LVL",label:"Latvian lats"},{value:"LYD",label:"Libyan dinar"},{value:"MAD",label:"Moroccan dirham"},{value:"MDL",label:"Moldovan leu"},{value:"MGA",label:"Malagasy ariary"},{value:"MKD",label:"Macedonian denar"},{value:"MMK",label:"Burmese kyat"},{value:"MNT",label:"Mongolian tögrög"},{value:"MOP",label:"Macanese pataca"},{value:"MRO",label:"Mauritanian ouguiya"},{value:"MUR",label:"Mauritian rupee"},{value:"MVR",label:"Maldivian rufiyaa"},{value:"MWK",label:"Malawian kwacha"},{value:"MYR",label:"Malaysian ringgit"},{value:"MZN",label:"Mozambican metical"},{value:"NAD",label:"Namibian dollar"},{value:"NGN",label:"Nigerian naira"},{value:"NIO",label:"Nicaraguan córdoba"},{value:"NOK",label:"Norwegian krone"},{value:"NPR",label:"Nepalese rupee"},{value:"NZD",label:"New Zealand dollar"},{value:"OMR",label:"Omani rial"},{value:"PAB",label:"Panamanian balboa"},{value:"PEN",label:"Peruvian nuevo sol"},{value:"PGK",label:"Papua New Guinean kina"},{value:"PHP",label:"Philippine peso"},{value:"PKR",label:"Pakistani rupee"},{value:"PLN",label:"Polish złoty"},{value:"PRB",label:"Transnistrian ruble"},{value:"PYG",label:"Paraguayan guaraní"},{value:"QAR",label:"Qatari riyal"},{value:"RON",label:"Romanian leu"},{value:"RSD",label:"Serbian dinar"},{value:"RUB",label:"Russian ruble"},{value:"RWF",label:"Rwandan franc"},{value:"SAR",label:"Saudi riyal"},{value:"SBD",label:"Solomon Islands dollar"},{value:"SCR",label:"Seychellois rupee"},{value:"SDG",label:"Singapore dollar"},{value:"SEK",label:"Swedish krona"},{value:"SGD",label:"Singapore dollar"},{value:"SHP",label:"Saint Helena pound"},{value:"SLL",label:"Sierra Leonean leone"},{value:"SOS",label:"Somali shilling"},{value:"SRD",label:"Surinamese dollar"},{value:"SSP",label:"South Sudanese pound"},{value:"STD",label:"São Tomé and Príncipe dobra"},{value:"SVC",label:"Salvadoran colón"},{value:"SYP",label:"Syrian pound"},{value:"SZL",label:"Swazi lilangeni"},{value:"THB",label:"Thai baht"},{value:"TJS",label:"Tajikistani somoni"},{value:"TMT",label:"Turkmenistan manat"},{value:"TND",label:"Tunisian dinar"},{value:"TOP",label:"Tongan paʻanga"},{value:"TRY",label:"Turkish lira"},{value:"TTD",label:"Trinidad and Tobago dollar"},{value:"TWD",label:"New Taiwan dollar"},{value:"TZS",label:"Tanzanian shilling"},{value:"UAH",label:"Ukrainian hryvnia"},{value:"UGX",label:"Ugandan shilling"},{value:"UYU",label:"Uruguayan peso"},{value:"UZS",label:"Uzbekistani som"},{value:"VEF",label:"Venezuelan bolívar"},{value:"VND",label:"Vietnamese đồng"},{value:"VUV",label:"Vanuatu vatu"},{value:"WST",label:"Samoan tālā"},{value:"XAF",label:"Central African CFA franc"},{value:"XCD",label:"East Caribbean dollar"},{value:"XOF",label:"West African CFA franc"},{value:"XPF",label:"CFP franc"},{value:"YER",label:"Yemeni rial"},{value:"ZAR",label:"South African rand"},{value:"ZMW",label:"Zambian kwacha"},{value:"ZWL",label:"Zimbabwean dollar"}]),r=[{value:"none",label:"None"},{value:"$",label:"$"},{value:"£",label:"£"},{value:"€",label:"€"},{value:"¥",label:"¥"},{value:"₱",label:"₱"},{value:"₩",label:"₩"},{value:"ƒ",label:"ƒ"},{value:"₦",label:"₦"}],o={currencyCodes:i,currencySymbols:r},u={name:"ListingsGeneral",inheritAttrs:!1,props:{currencyCodeSelected:{type:String,default:"none"},currencySymbolSelected:{type:String,default:"none"},displayCurrencyCode:{type:Boolean,default:!1},defaultDisclaimer:{type:String,default:""},numberOfPosts:{type:[Number,String],default:"9"},listingSlug:{type:String,default:"listings"},defaultState:{type:String,default:""},formDisabled:{type:Boolean,default:!1}},created:function(){this.currency=o}},s=u,d=(l("db11"),l("2877")),c=Object(d["a"])(s,t,n,!1,null,null,null);a["a"]=c.exports},"078c":function(e,a,l){"use strict";l("c5ee")},1331:function(e,a,l){"use strict";l.r(a);var t=function(){var e=this,a=e.$createElement,l=e._self._c||a;return l("GuidedSetupContentCard",{attrs:{cardTitle:e.cardTitle,steps:e.guidedSetupSteps},on:{"back-step":e.goBackStep,"skip-step":e.goSkipStep,continue:function(a){return e.saveHandler("listingsGeneral","listingsSettings","general")}},scopedSlots:e._u([{key:"controls",fn:function(){return[l("ListingsGeneral",e._b({attrs:{formDisabled:e.formDisabled},on:{"form-field-update":e.formUpdate}},"ListingsGeneral",e.localStateValues,!1))]},proxy:!0}])})},n=[],i=(l("96cf"),l("1da1")),r=l("5530"),o=l("2f62"),u=l("12e8"),s=l("fa47"),d=l("b387"),c=l("0633"),b=l("8be2"),p={name:"guided-setup-listings-general",inject:[u["a"].listingsSettings.repo],mixins:[s["a"],d["a"]],components:{ListingsGeneral:c["a"],GuidedSetupContentCard:b["a"]},data:function(){return{formDisabled:!1}},computed:Object(r["a"])({},Object(o["d"])({guidedSetupSteps:function(e){return e.guidedSetup.guidedSetupSteps}})),methods:Object(r["a"])({},Object(o["b"])({progressStepperUpdate:"guidedSetup/progressStepperUpdate"})),created:function(){var e=this;return Object(i["a"])(regeneratorRuntime.mark((function a(){var l,t;return regeneratorRuntime.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return e.module="listingsGeneral",e.cardTitle="Configure IMPress Listings",e.continuePath="/guided-setup/listings/idx",e.skipPath="/guided-setup/agents",a.next=6,e.listingsSettingsRepository.get("general");case 6:l=a.sent,t=l.data,e.updateState(t);case 9:case"end":return a.stop()}}),a)})))()},mounted:function(){this.progressStepperUpdate([4,2,0,0])}},v=p,f=l("2877"),m=Object(f["a"])(v,t,n,!1,null,null,null);a["default"]=m.exports},"33ff":function(e,a,l){},"7a2e":function(e,a,l){"use strict";l("e35d")},"8be2":function(e,a,l){"use strict";var t=function(){var e=this,a=e.$createElement,l=e._self._c||a;return l("idx-dialog",{attrs:{show:!0,customClass:"gs-dialog"},on:{dismiss:e.closeDialog},scopedSlots:e._u([{key:"header",fn:function(){return[l("idx-block",{attrs:{className:"dialog-header"}},[l("idx-block",{attrs:{className:"dialog-header__title"}},[e._v(e._s(e.title))]),l("idx-block",{attrs:{className:"dialog-header__dismiss"}},[l("span",{on:{click:e.closeDialog}},[e._v("Close ×")])])],1)]},proxy:!0}])},[l("ContentCard",{attrs:{steps:e.steps,cardTitle:e.cardTitle,relatedLinks:e.relatedLinks},on:{"back-step":function(a){return e.$emit("back-step")},"skip-step":function(a){return e.$emit("skip-step")},continue:function(a){return e.$emit("continue")}},scopedSlots:e._u([{key:"description",fn:function(){return[e._t("description")]},proxy:!0},{key:"controls",fn:function(){return[e._t("controls")]},proxy:!0}],null,!0)})],1)},n=[],i=l("5530"),r=function(){var e=this,a=e.$createElement,l=e._self._c||a;return l("idx-block",{attrs:{className:"content-card"}},[l("idx-block",{attrs:{className:"content-card__stepper"}},e._l(e.steps,(function(a){return l("idx-progress-stepper",e._b({key:a.name,scopedSlots:e._u([{key:"complete",fn:function(){return[l("svg-icon",{attrs:{icon:"check"}})]},proxy:!0},{key:"icon",fn:function(){return[l("svg-icon",{attrs:{icon:a.icon}})]},proxy:!0}],null,!0)},"idx-progress-stepper",Object.assign({},a),!1))})),1),l("idx-block",{attrs:{className:"content-card__content",role:"tabpanel"}},[l("h1",[e._v(e._s(e.cardTitle))]),e._t("description"),e._t("controls")],2),l("idx-block",{attrs:{className:"content-card__sidebar"}},[l("RelatedLinks",{attrs:{relatedLinks:e.relatedLinks}})],1),l("idx-block",{attrs:{className:"content-card__footer"}},[l("idx-block",{attrs:{className:"content-card__buttons"}},[l("idx-button",{attrs:{size:"lg",theme:"light"},on:{click:function(a){return e.$emit("back-step")}}},[e._v("← Back")]),l("idx-button",{attrs:{size:"lg",theme:"link",customClass:"btn-link"},on:{click:function(a){return e.$emit("skip-step")}}},[e._v("Skip")]),l("idx-button",{attrs:{size:"lg"},on:{click:function(a){return e.$emit("continue")}}},[e._v("Continue")])],1)],1)],1)},o=[],u=l("bb2b"),s=l("0032"),d={name:"ContentCard",components:{RelatedLinks:u["a"],SvgIcon:s["a"]},props:{cardTitle:{type:String,default:""},steps:{type:Array,default:function(){return[]}},relatedLinks:{type:Array,default:function(){return[]}}},mounted:function(){document.body.classList.add("".concat(this.$idxStrap.prefix,"modal-open"))},beforeDestroy:function(){document.body.classList.remove("".concat(this.$idxStrap.prefix,"modal-open"))}},c=d,b=(l("eb98"),l("2877")),p=Object(b["a"])(c,r,o,!1,null,null,null),v=p.exports,f=l("2f62"),m={name:"GuidedSetupContentCard",components:{ContentCard:v},props:{cardTitle:{type:String,default:""},relatedLinks:{type:Array,default:function(){return[]}},steps:{type:Array,default:function(){return[]}}},data:function(){return{title:"IMPress for IDX Broker Setup"}},computed:Object(i["a"])({},Object(f["c"])({changedModules:"guidedSetup/changedModules"})),methods:Object(i["a"])(Object(i["a"])({},Object(f["b"])({setItem:"guidedSetup/setItem"})),{},{closeDialog:function(){for(var e=0;e0}},methods:{formUpdate:function(e){var a=Object(t["a"])({},e.key,e.value);this.formChanges=Object(n["a"])(Object(n["a"])({},this.formChanges),a)}},beforeRouteLeave:function(e,a,l){if(this.formIsUpdated){var t=window.confirm("Do you really want to leave? You have unsaved changes!");t?l():l(!1)}else l()}}},bb2b:function(e,a,l){"use strict";var t=function(){var e=this,a=e.$createElement,l=e._self._c||a;return l("idx-card",[l("idx-card-header",[e._v(e._s(e.title))]),l("idx-card-body",[l("idx-list",{attrs:{unstyled:""}},[e._l(e.relatedLinks,(function(a){return l("idx-list-item",{key:a.href},[l("a",{attrs:{href:a.href,target:"_blank"}},[e._v(e._s(a.text))])])})),l("idx-list-item",[l("a",{attrs:{href:"https://middleware.idxbroker.com/mgmt/",target:"_blank"}},[e._v("IDX Broker Middleware")])]),l("idx-list-item",[l("a",{attrs:{href:"https://www.idxbroker.com/",target:"_blank"}},[e._v("Sign up for IDX Broker")])])],2)],1)],1)},n=[],i={name:"RelatedLinks",props:{title:{type:String,default:"Related Links"},relatedLinks:{type:Array,default:function(){return[]}}}},r=i,o=(l("078c"),l("2877")),u=Object(o["a"])(r,t,n,!1,null,"28b01ccf",null);a["a"]=u.exports},c5ee:function(e,a,l){},d537:function(e,a,l){},d90c:function(e,a,l){},db11:function(e,a,l){"use strict";l("d90c")},e35d:function(e,a,l){},eb98:function(e,a,l){"use strict";l("d537")},fa47:function(e,a,l){"use strict";var t=l("5530"),n=l("2f62");a["a"]={computed:Object(t["a"])({},Object(n["d"])({hasChanges:function(e){return e.guidedSetup.hasChanges}})),methods:{goBackStep:function(){this.$router.go(-1)},goSkipStep:function(){this.$router.push({path:this.skipPath})},updateState:function(e){for(var a in e)this.$store.dispatch("".concat(this.module,"/setItem"),{key:a,value:e[a]})},saveAction:function(){this.updateState(this.formChanges),this.formChanges={}},saveHandler:function(e){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";this.formIsUpdated?(this.$store.dispatch("guidedSetup/setItem",{key:"hasChanges",value:!0}),this.$store.dispatch("guidedSetup/setItem",{key:e,value:{changes:"omnibar"===e?this.localStateValues:this.formChanges,module:""!==a?a:this.module,path:l}}),this.formChanges={},this.$router.push({path:this.continuePath})):this.$router.push({path:this.continuePath})}},beforeRouteLeave:function(e,a,l){if("/settings/general"===e.path&&this.hasChanges){var t=window.confirm("Do you really want to leave? You have unsaved changes!");t?l():l(!1)}else l()}}}}]); //# sourceMappingURL=chunk-453a8273.14649de2.js.map/** * Deprecated functions * * Where functions come to die. * * @author Automattic * @category Core * @package WooCommerce\Functions * @version 3.3.0 */ use Automattic\Jetpack\Constants; if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Runs a deprecated action with notice only if used. * * @since 3.0.0 * @param string $tag The name of the action hook. * @param array $args Array of additional function arguments to be passed to do_action(). * @param string $version The version of WooCommerce that deprecated the hook. * @param string $replacement The hook that should have been used. * @param string $message A message regarding the change. */ function wc_do_deprecated_action( $tag, $args, $version, $replacement = null, $message = null ) { if ( ! has_action( $tag ) ) { return; } wc_deprecated_hook( $tag, $version, $replacement, $message ); do_action_ref_array( $tag, $args ); } /** * Wrapper for deprecated functions so we can apply some extra logic. * * @since 3.0.0 * @param string $function Function used. * @param string $version Version the message was added in. * @param string $replacement Replacement for the called function. */ function wc_deprecated_function( $function, $version, $replacement = null ) { // @codingStandardsIgnoreStart if ( wp_doing_ajax() || WC()->is_rest_api_request() ) { do_action( 'deprecated_function_run', $function, $replacement, $version ); $log_string = "The {$function} function is deprecated since version {$version}."; $log_string .= $replacement ? " Replace with {$replacement}." : ''; error_log( $log_string ); } else { _deprecated_function( $function, $version, $replacement ); } // @codingStandardsIgnoreEnd } /** * Wrapper for deprecated hook so we can apply some extra logic. * * @since 3.3.0 * @param string $hook The hook that was used. * @param string $version The version of WordPress that deprecated the hook. * @param string $replacement The hook that should have been used. * @param string $message A message regarding the change. */ function wc_deprecated_hook( $hook, $version, $replacement = null, $message = null ) { // @codingStandardsIgnoreStart if ( wp_doing_ajax() || WC()->is_rest_api_request() ) { do_action( 'deprecated_hook_run', $hook, $replacement, $version, $message ); $message = empty( $message ) ? '' : ' ' . $message; $log_string = "{$hook} is deprecated since version {$version}"; $log_string .= $replacement ? "! Use {$replacement} instead." : ' with no alternative available.'; error_log( $log_string . $message ); } else { _deprecated_hook( $hook, $version, $replacement, $message ); } // @codingStandardsIgnoreEnd } /** * When catching an exception, this allows us to log it if unexpected. * * @since 3.3.0 * @param Exception $exception_object The exception object. * @param string $function The function which threw exception. * @param array $args The args passed to the function. */ function wc_caught_exception( $exception_object, $function = '', $args = array() ) { // @codingStandardsIgnoreStart $message = $exception_object->getMessage(); $message .= '. Args: ' . print_r( $args, true ) . '.'; do_action( 'woocommerce_caught_exception', $exception_object, $function, $args ); error_log( "Exception caught in {$function}. {$message}." ); // @codingStandardsIgnoreEnd } /** * Wrapper for _doing_it_wrong(). * * @since 3.0.0 * @param string $function Function used. * @param string $message Message to log. * @param string $version Version the message was added in. */ function wc_doing_it_wrong( $function, $message, $version ) { // @codingStandardsIgnoreStart $message .= ' Backtrace: ' . wp_debug_backtrace_summary(); if ( wp_doing_ajax() || WC()->is_rest_api_request() ) { do_action( 'doing_it_wrong_run', $function, $message, $version ); error_log( "{$function} was called incorrectly. {$message}. This message was added in version {$version}." ); } else { _doing_it_wrong( $function, $message, $version ); } // @codingStandardsIgnoreEnd } /** * Wrapper for deprecated arguments so we can apply some extra logic. * * @since 3.0.0 * @param string $argument * @param string $version * @param string $replacement */ function wc_deprecated_argument( $argument, $version, $message = null ) { if ( wp_doing_ajax() || WC()->is_rest_api_request() ) { do_action( 'deprecated_argument_run', $argument, $message, $version ); error_log( "The {$argument} argument is deprecated since version {$version}. {$message}" ); } else { _deprecated_argument( $argument, $version, $message ); } } /** * @deprecated 2.1 */ function woocommerce_show_messages() { wc_deprecated_function( 'woocommerce_show_messages', '2.1', 'wc_print_notices' ); wc_print_notices(); } /** * @deprecated 2.1 */ function woocommerce_weekend_area_js() { wc_deprecated_function( 'woocommerce_weekend_area_js', '2.1' ); } /** * @deprecated 2.1 */ function woocommerce_tooltip_js() { wc_deprecated_function( 'woocommerce_tooltip_js', '2.1' ); } /** * @deprecated 2.1 */ function woocommerce_datepicker_js() { wc_deprecated_function( 'woocommerce_datepicker_js', '2.1' ); } /** * @deprecated 2.1 */ function woocommerce_admin_scripts() { wc_deprecated_function( 'woocommerce_admin_scripts', '2.1' ); } /** * @deprecated 2.1 */ function woocommerce_create_page( $slug, $option = '', $page_title = '', $page_content = '', $post_parent = 0 ) { wc_deprecated_function( 'woocommerce_create_page', '2.1', 'wc_create_page' ); return wc_create_page( $slug, $option, $page_title, $page_content, $post_parent ); } /** * @deprecated 2.1 */ function woocommerce_readfile_chunked( $file, $retbytes = true ) { wc_deprecated_function( 'woocommerce_readfile_chunked', '2.1', 'WC_Download_Handler::readfile_chunked()' ); return WC_Download_Handler::readfile_chunked( $file ); } /** * Formal total costs - format to the number of decimal places for the base currency. * * @access public * @param mixed $number * @deprecated 2.1 * @return string */ function woocommerce_format_total( $number ) { wc_deprecated_function( __FUNCTION__, '2.1', 'wc_format_decimal()' ); return wc_format_decimal( $number, wc_get_price_decimals(), false ); } /** * Get product name with extra details such as SKU price and attributes. Used within admin. * * @access public * @param WC_Product $product * @deprecated 2.1 * @return string */ function woocommerce_get_formatted_product_name( $product ) { wc_deprecated_function( __FUNCTION__, '2.1', 'WC_Product::get_formatted_name()' ); return $product->get_formatted_name(); } /** * Handle IPN requests for the legacy paypal gateway by calling gateways manually if needed. * * @access public */ function woocommerce_legacy_paypal_ipn() { if ( ! empty( $_GET['paypalListener'] ) && 'paypal_standard_IPN' === $_GET['paypalListener'] ) { WC()->payment_gateways(); do_action( 'woocommerce_api_wc_gateway_paypal' ); } } add_action( 'init', 'woocommerce_legacy_paypal_ipn' ); /** * @deprecated 3.0 */ function get_product( $the_product = false, $args = array() ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_product' ); return wc_get_product( $the_product, $args ); } /** * @deprecated 3.0 */ function woocommerce_protected_product_add_to_cart( $passed, $product_id ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_protected_product_add_to_cart' ); return wc_protected_product_add_to_cart( $passed, $product_id ); } /** * @deprecated 3.0 */ function woocommerce_empty_cart() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_empty_cart' ); wc_empty_cart(); } /** * @deprecated 3.0 */ function woocommerce_load_persistent_cart( $user_login, $user = 0 ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_load_persistent_cart' ); return wc_load_persistent_cart( $user_login, $user ); } /** * @deprecated 3.0 */ function woocommerce_add_to_cart_message( $product_id ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_add_to_cart_message' ); wc_add_to_cart_message( $product_id ); } /** * @deprecated 3.0 */ function woocommerce_clear_cart_after_payment() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_clear_cart_after_payment' ); wc_clear_cart_after_payment(); } /** * @deprecated 3.0 */ function woocommerce_cart_totals_subtotal_html() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_subtotal_html' ); wc_cart_totals_subtotal_html(); } /** * @deprecated 3.0 */ function woocommerce_cart_totals_shipping_html() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_shipping_html' ); wc_cart_totals_shipping_html(); } /** * @deprecated 3.0 */ function woocommerce_cart_totals_coupon_html( $coupon ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_coupon_html' ); wc_cart_totals_coupon_html( $coupon ); } /** * @deprecated 3.0 */ function woocommerce_cart_totals_order_total_html() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_order_total_html' ); wc_cart_totals_order_total_html(); } /** * @deprecated 3.0 */ function woocommerce_cart_totals_fee_html( $fee ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_fee_html' ); wc_cart_totals_fee_html( $fee ); } /** * @deprecated 3.0 */ function woocommerce_cart_totals_shipping_method_label( $method ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_shipping_method_label' ); return wc_cart_totals_shipping_method_label( $method ); } /** * @deprecated 3.0 */ function woocommerce_get_template_part( $slug, $name = '' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_template_part' ); wc_get_template_part( $slug, $name ); } /** * @deprecated 3.0 */ function woocommerce_get_template( $template_name, $args = array(), $template_path = '', $default_path = '' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_template' ); wc_get_template( $template_name, $args, $template_path, $default_path ); } /** * @deprecated 3.0 */ function woocommerce_locate_template( $template_name, $template_path = '', $default_path = '' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_locate_template' ); return wc_locate_template( $template_name, $template_path, $default_path ); } /** * @deprecated 3.0 */ function woocommerce_mail( $to, $subject, $message, $headers = "Content-Type: text/html\r\n", $attachments = "" ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_mail' ); wc_mail( $to, $subject, $message, $headers, $attachments ); } /** * @deprecated 3.0 */ function woocommerce_disable_admin_bar( $show_admin_bar ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_disable_admin_bar' ); return wc_disable_admin_bar( $show_admin_bar ); } /** * @deprecated 3.0 */ function woocommerce_create_new_customer( $email, $username = '', $password = '' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_create_new_customer' ); return wc_create_new_customer( $email, $username, $password ); } /** * @deprecated 3.0 */ function woocommerce_set_customer_auth_cookie( $customer_id ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_set_customer_auth_cookie' ); wc_set_customer_auth_cookie( $customer_id ); } /** * @deprecated 3.0 */ function woocommerce_update_new_customer_past_orders( $customer_id ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_update_new_customer_past_orders' ); return wc_update_new_customer_past_orders( $customer_id ); } /** * @deprecated 3.0 */ function woocommerce_paying_customer( $order_id ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_paying_customer' ); wc_paying_customer( $order_id ); } /** * @deprecated 3.0 */ function woocommerce_customer_bought_product( $customer_email, $user_id, $product_id ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_customer_bought_product' ); return wc_customer_bought_product( $customer_email, $user_id, $product_id ); } /** * @deprecated 3.0 */ function woocommerce_customer_has_capability( $allcaps, $caps, $args ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_customer_has_capability' ); return wc_customer_has_capability( $allcaps, $caps, $args ); } /** * @deprecated 3.0 */ function woocommerce_sanitize_taxonomy_name( $taxonomy ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_sanitize_taxonomy_name' ); return wc_sanitize_taxonomy_name( $taxonomy ); } /** * @deprecated 3.0 */ function woocommerce_get_filename_from_url( $file_url ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_filename_from_url' ); return wc_get_filename_from_url( $file_url ); } /** * @deprecated 3.0 */ function woocommerce_get_dimension( $dim, $to_unit ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_dimension' ); return wc_get_dimension( $dim, $to_unit ); } /** * @deprecated 3.0 */ function woocommerce_get_weight( $weight, $to_unit ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_weight' ); return wc_get_weight( $weight, $to_unit ); } /** * @deprecated 3.0 */ function woocommerce_trim_zeros( $price ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_trim_zeros' ); return wc_trim_zeros( $price ); } /** * @deprecated 3.0 */ function woocommerce_round_tax_total( $tax ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_round_tax_total' ); return wc_round_tax_total( $tax ); } /** * @deprecated 3.0 */ function woocommerce_format_decimal( $number, $dp = false, $trim_zeros = false ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_format_decimal' ); return wc_format_decimal( $number, $dp, $trim_zeros ); } /** * @deprecated 3.0 */ function woocommerce_clean( $var ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_clean' ); return wc_clean( $var ); } /** * @deprecated 3.0 */ function woocommerce_array_overlay( $a1, $a2 ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_array_overlay' ); return wc_array_overlay( $a1, $a2 ); } /** * @deprecated 3.0 */ function woocommerce_price( $price, $args = array() ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_price' ); return wc_price( $price, $args ); } /** * @deprecated 3.0 */ function woocommerce_let_to_num( $size ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_let_to_num' ); return wc_let_to_num( $size ); } /** * @deprecated 3.0 */ function woocommerce_date_format() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_date_format' ); return wc_date_format(); } /** * @deprecated 3.0 */ function woocommerce_time_format() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_time_format' ); return wc_time_format(); } /** * @deprecated 3.0 */ function woocommerce_timezone_string() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_timezone_string' ); return wc_timezone_string(); } if ( ! function_exists( 'woocommerce_rgb_from_hex' ) ) { /** * @deprecated 3.0 */ function woocommerce_rgb_from_hex( $color ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_rgb_from_hex' ); return wc_rgb_from_hex( $color ); } } if ( ! function_exists( 'woocommerce_hex_darker' ) ) { /** * @deprecated 3.0 */ function woocommerce_hex_darker( $color, $factor = 30 ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_hex_darker' ); return wc_hex_darker( $color, $factor ); } } if ( ! function_exists( 'woocommerce_hex_lighter' ) ) { /** * @deprecated 3.0 */ function woocommerce_hex_lighter( $color, $factor = 30 ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_hex_lighter' ); return wc_hex_lighter( $color, $factor ); } } if ( ! function_exists( 'woocommerce_light_or_dark' ) ) { /** * @deprecated 3.0 */ function woocommerce_light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_light_or_dark' ); return wc_light_or_dark( $color, $dark, $light ); } } if ( ! function_exists( 'woocommerce_format_hex' ) ) { /** * @deprecated 3.0 */ function woocommerce_format_hex( $hex ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_format_hex' ); return wc_format_hex( $hex ); } } /** * @deprecated 3.0 */ function woocommerce_get_order_id_by_order_key( $order_key ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_order_id_by_order_key' ); return wc_get_order_id_by_order_key( $order_key ); } /** * @deprecated 3.0 */ function woocommerce_downloadable_file_permission( $download_id, $product_id, $order ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_downloadable_file_permission' ); return wc_downloadable_file_permission( $download_id, $product_id, $order ); } /** * @deprecated 3.0 */ function woocommerce_downloadable_product_permissions( $order_id ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_downloadable_product_permissions' ); wc_downloadable_product_permissions( $order_id ); } /** * @deprecated 3.0 */ function woocommerce_add_order_item( $order_id, $item ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_add_order_item' ); return wc_add_order_item( $order_id, $item ); } /** * @deprecated 3.0 */ function woocommerce_delete_order_item( $item_id ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_delete_order_item' ); return wc_delete_order_item( $item_id ); } /** * @deprecated 3.0 */ function woocommerce_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_update_order_item_meta' ); return wc_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value ); } /** * @deprecated 3.0 */ function woocommerce_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = false ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_add_order_item_meta' ); return wc_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique ); } /** * @deprecated 3.0 */ function woocommerce_delete_order_item_meta( $item_id, $meta_key, $meta_value = '', $delete_all = false ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_delete_order_item_meta' ); return wc_delete_order_item_meta( $item_id, $meta_key, $meta_value, $delete_all ); } /** * @deprecated 3.0 */ function woocommerce_get_order_item_meta( $item_id, $key, $single = true ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_order_item_meta' ); return wc_get_order_item_meta( $item_id, $key, $single ); } /** * @deprecated 3.0 */ function woocommerce_cancel_unpaid_orders() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cancel_unpaid_orders' ); wc_cancel_unpaid_orders(); } /** * @deprecated 3.0 */ function woocommerce_processing_order_count() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_processing_order_count' ); return wc_processing_order_count(); } /** * @deprecated 3.0 */ function woocommerce_get_page_id( $page ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_page_id' ); return wc_get_page_id( $page ); } /** * @deprecated 3.0 */ function woocommerce_get_endpoint_url( $endpoint, $value = '', $permalink = '' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_endpoint_url' ); return wc_get_endpoint_url( $endpoint, $value, $permalink ); } /** * @deprecated 3.0 */ function woocommerce_lostpassword_url( $url ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_lostpassword_url' ); return wc_lostpassword_url( $url ); } /** * @deprecated 3.0 */ function woocommerce_customer_edit_account_url() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_customer_edit_account_url' ); return wc_customer_edit_account_url(); } /** * @deprecated 3.0 */ function woocommerce_nav_menu_items( $items, $args ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_nav_menu_items' ); return wc_nav_menu_items( $items ); } /** * @deprecated 3.0 */ function woocommerce_nav_menu_item_classes( $menu_items, $args ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_nav_menu_item_classes' ); return wc_nav_menu_item_classes( $menu_items ); } /** * @deprecated 3.0 */ function woocommerce_list_pages( $pages ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_list_pages' ); return wc_list_pages( $pages ); } /** * @deprecated 3.0 */ function woocommerce_product_dropdown_categories( $args = array(), $deprecated_hierarchical = 1, $deprecated_show_uncategorized = 1, $deprecated_orderby = '' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_product_dropdown_categories' ); return wc_product_dropdown_categories( $args, $deprecated_hierarchical, $deprecated_show_uncategorized, $deprecated_orderby ); } /** * @deprecated 3.0 */ function woocommerce_walk_category_dropdown_tree( $a1 = '', $a2 = '', $a3 = '' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_walk_category_dropdown_tree' ); return wc_walk_category_dropdown_tree( $a1, $a2, $a3 ); } /** * @deprecated 3.0 */ function woocommerce_taxonomy_metadata_wpdbfix() { wc_deprecated_function( __FUNCTION__, '3.0' ); } /** * @deprecated 3.0 */ function wc_taxonomy_metadata_wpdbfix() { wc_deprecated_function( __FUNCTION__, '3.0' ); } /** * @deprecated 3.0 */ function woocommerce_order_terms( $the_term, $next_id, $taxonomy, $index = 0, $terms = null ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_reorder_terms' ); return wc_reorder_terms( $the_term, $next_id, $taxonomy, $index, $terms ); } /** * @deprecated 3.0 */ function woocommerce_set_term_order( $term_id, $index, $taxonomy, $recursive = false ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_set_term_order' ); return wc_set_term_order( $term_id, $index, $taxonomy, $recursive ); } /** * @deprecated 3.0 */ function woocommerce_terms_clauses( $clauses, $taxonomies, $args ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_terms_clauses' ); return wc_terms_clauses( $clauses, $taxonomies, $args ); } /** * @deprecated 3.0 */ function _woocommerce_term_recount( $terms, $taxonomy, $callback, $terms_are_term_taxonomy_ids ) { wc_deprecated_function( __FUNCTION__, '3.0', '_wc_term_recount' ); return _wc_term_recount( $terms, $taxonomy, $callback, $terms_are_term_taxonomy_ids ); } /** * @deprecated 3.0 */ function woocommerce_recount_after_stock_change( $product_id ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_recount_after_stock_change' ); return wc_recount_after_stock_change( $product_id ); } /** * @deprecated 3.0 */ function woocommerce_change_term_counts( $terms, $taxonomies, $args ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_change_term_counts' ); return wc_change_term_counts( $terms, $taxonomies ); } /** * @deprecated 3.0 */ function woocommerce_get_product_ids_on_sale() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_product_ids_on_sale' ); return wc_get_product_ids_on_sale(); } /** * @deprecated 3.0 */ function woocommerce_get_featured_product_ids() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_featured_product_ids' ); return wc_get_featured_product_ids(); } /** * @deprecated 3.0 */ function woocommerce_get_product_terms( $object_id, $taxonomy, $fields = 'all' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_product_terms' ); return wc_get_product_terms( $object_id, $taxonomy, array( 'fields' => $fields ) ); } /** * @deprecated 3.0 */ function woocommerce_product_post_type_link( $permalink, $post ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_product_post_type_link' ); return wc_product_post_type_link( $permalink, $post ); } /** * @deprecated 3.0 */ function woocommerce_placeholder_img_src() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_placeholder_img_src' ); return wc_placeholder_img_src(); } /** * @deprecated 3.0 */ function woocommerce_placeholder_img( $size = 'woocommerce_thumbnail' ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_placeholder_img' ); return wc_placeholder_img( $size ); } /** * @deprecated 3.0 */ function woocommerce_get_formatted_variation( $variation = '', $flat = false ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_formatted_variation' ); return wc_get_formatted_variation( $variation, $flat ); } /** * @deprecated 3.0 */ function woocommerce_scheduled_sales() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_scheduled_sales' ); return wc_scheduled_sales(); } /** * @deprecated 3.0 */ function woocommerce_get_attachment_image_attributes( $attr ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_attachment_image_attributes' ); return wc_get_attachment_image_attributes( $attr ); } /** * @deprecated 3.0 */ function woocommerce_prepare_attachment_for_js( $response ) { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_prepare_attachment_for_js' ); return wc_prepare_attachment_for_js( $response ); } /** * @deprecated 3.0 */ function woocommerce_track_product_view() { wc_deprecated_function( __FUNCTION__, '3.0', 'wc_track_product_view' ); return wc_track_product_view(); } /** * @deprecated 2.3 has no replacement */ function woocommerce_compile_less_styles() { wc_deprecated_function( 'woocommerce_compile_less_styles', '2.3' ); } /** * woocommerce_calc_shipping was an option used to determine if shipping was enabled prior to version 2.6.0. This has since been replaced with wc_shipping_enabled() function and * the woocommerce_ship_to_countries setting. * @deprecated 2.6.0 * @return string */ function woocommerce_calc_shipping_backwards_compatibility( $value ) { if ( Constants::is_defined( 'WC_UPDATING' ) ) { return $value; } return 'disabled' === get_option( 'woocommerce_ship_to_countries' ) ? 'no' : 'yes'; } add_filter( 'pre_option_woocommerce_calc_shipping', 'woocommerce_calc_shipping_backwards_compatibility' ); /** * @deprecated 3.0.0 * @see WC_Structured_Data class * * @return string */ function woocommerce_get_product_schema() { wc_deprecated_function( 'woocommerce_get_product_schema', '3.0' ); global $product; $schema = "Product"; // Downloadable product schema handling if ( $product->is_downloadable() ) { switch ( $product->download_type ) { case 'application' : $schema = "SoftwareApplication"; break; case 'music' : $schema = "MusicAlbum"; break; default : $schema = "Product"; break; } } return 'http://schema.org/' . $schema; } /** * Save product price. * * This is a private function (internal use ONLY) used until a data manipulation api is built. * * @deprecated 3.0.0 * @param int $product_id * @param float $regular_price * @param float $sale_price * @param string $date_from * @param string $date_to */ function _wc_save_product_price( $product_id, $regular_price, $sale_price = '', $date_from = '', $date_to = '' ) { wc_doing_it_wrong( '_wc_save_product_price()', 'This function is not for developer use and is deprecated.', '3.0' ); $product_id = absint( $product_id ); $regular_price = wc_format_decimal( $regular_price ); $sale_price = '' === $sale_price ? '' : wc_format_decimal( $sale_price ); $date_from = wc_clean( $date_from ); $date_to = wc_clean( $date_to ); update_post_meta( $product_id, '_regular_price', $regular_price ); update_post_meta( $product_id, '_sale_price', $sale_price ); // Save Dates update_post_meta( $product_id, '_sale_price_dates_from', $date_from ? strtotime( $date_from ) : '' ); update_post_meta( $product_id, '_sale_price_dates_to', $date_to ? strtotime( $date_to ) : '' ); if ( $date_to && ! $date_from ) { $date_from = strtotime( 'NOW', current_time( 'timestamp' ) ); update_post_meta( $product_id, '_sale_price_dates_from', $date_from ); } // Update price if on sale if ( '' !== $sale_price && '' === $date_to && '' === $date_from ) { update_post_meta( $product_id, '_price', $sale_price ); } else { update_post_meta( $product_id, '_price', $regular_price ); } if ( '' !== $sale_price && $date_from && strtotime( $date_from ) < strtotime( 'NOW', current_time( 'timestamp' ) ) ) { update_post_meta( $product_id, '_price', $sale_price ); } if ( $date_to && strtotime( $date_to ) < strtotime( 'NOW', current_time( 'timestamp' ) ) ) { update_post_meta( $product_id, '_price', $regular_price ); update_post_meta( $product_id, '_sale_price_dates_from', '' ); update_post_meta( $product_id, '_sale_price_dates_to', '' ); } } /** * Return customer avatar URL. * * @deprecated 3.1.0 * @since 2.6.0 * @param string $email the customer's email. * @return string the URL to the customer's avatar. */ function wc_get_customer_avatar_url( $email ) { // Deprecated in favor of WordPress get_avatar_url() function. wc_deprecated_function( 'wc_get_customer_avatar_url()', '3.1', 'get_avatar_url()' ); return get_avatar_url( $email ); } /** * WooCommerce Core Supported Themes. * * @deprecated 3.3.0 * @since 2.2 * @return string[] */ function wc_get_core_supported_themes() { wc_deprecated_function( 'wc_get_core_supported_themes()', '3.3' ); return array( 'twentyseventeen', 'twentysixteen', 'twentyfifteen', 'twentyfourteen', 'twentythirteen', 'twentyeleven', 'twentytwelve', 'twentyten' ); } /** * Get min/max price meta query args. * * @deprecated 3.6.0 * @since 3.0.0 * @param array $args Min price and max price arguments. * @return array */ function wc_get_min_max_price_meta_query( $args ) { wc_deprecated_function( 'wc_get_min_max_price_meta_query()', '3.6' ); $current_min_price = isset( $args['min_price'] ) ? floatval( $args['min_price'] ) : 0; $current_max_price = isset( $args['max_price'] ) ? floatval( $args['max_price'] ) : PHP_INT_MAX; return apply_filters( 'woocommerce_get_min_max_price_meta_query', array( 'key' => '_price', 'value' => array( $current_min_price, $current_max_price ), 'compare' => 'BETWEEN', 'type' => 'DECIMAL(10,' . wc_get_price_decimals() . ')', ), $args ); } /** * When a term is split, ensure meta data maintained. * * @deprecated 3.6.0 * @param int $old_term_id Old term ID. * @param int $new_term_id New term ID. * @param string $term_taxonomy_id Term taxonomy ID. * @param string $taxonomy Taxonomy. */ function wc_taxonomy_metadata_update_content_for_split_terms( $old_term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) { wc_deprecated_function( 'wc_taxonomy_metadata_update_content_for_split_terms', '3.6' ); } /** * WooCommerce Term Meta API. * * WC tables for storing term meta are deprecated from WordPress 4.4 since 4.4 has its own table. * This function serves as a wrapper, using the new table if present, or falling back to the WC table. * * @deprecated 3.6.0 * @param int $term_id Term ID. * @param string $meta_key Meta key. * @param mixed $meta_value Meta value. * @param string $prev_value Previous value. (default: ''). * @return bool */ function update_woocommerce_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) { wc_deprecated_function( 'update_woocommerce_term_meta', '3.6', 'update_term_meta' ); return function_exists( 'update_term_meta' ) ? update_term_meta( $term_id, $meta_key, $meta_value, $prev_value ) : update_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $prev_value ); } /** * WooCommerce Term Meta API. * * WC tables for storing term meta are deprecated from WordPress 4.4 since 4.4 has its own table. * This function serves as a wrapper, using the new table if present, or falling back to the WC table. * * @deprecated 3.6.0 * @param int $term_id Term ID. * @param string $meta_key Meta key. * @param mixed $meta_value Meta value. * @param bool $unique Make meta key unique. (default: false). * @return bool */ function add_woocommerce_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) { wc_deprecated_function( 'add_woocommerce_term_meta', '3.6', 'add_term_meta' ); return function_exists( 'add_term_meta' ) ? add_term_meta( $term_id, $meta_key, $meta_value, $unique ) : add_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $unique ); } /** * WooCommerce Term Meta API * * WC tables for storing term meta are deprecated from WordPress 4.4 since 4.4 has its own table. * This function serves as a wrapper, using the new table if present, or falling back to the WC table. * * @deprecated 3.6.0 * @param int $term_id Term ID. * @param string $meta_key Meta key. * @param mixed $meta_value Meta value (default: ''). * @param bool $deprecated Deprecated param (default: false). * @return bool */ function delete_woocommerce_term_meta( $term_id, $meta_key, $meta_value = '', $deprecated = false ) { wc_deprecated_function( 'delete_woocommerce_term_meta', '3.6', 'delete_term_meta' ); return function_exists( 'delete_term_meta' ) ? delete_term_meta( $term_id, $meta_key, $meta_value ) : delete_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value ); } /** * WooCommerce Term Meta API * * WC tables for storing term meta are deprecated from WordPress 4.4 since 4.4 has its own table. * This function serves as a wrapper, using the new table if present, or falling back to the WC table. * * @deprecated 3.6.0 * @param int $term_id Term ID. * @param string $key Meta key. * @param bool $single Whether to return a single value. (default: true). * @return mixed */ function get_woocommerce_term_meta( $term_id, $key, $single = true ) { wc_deprecated_function( 'get_woocommerce_term_meta', '3.6', 'get_term_meta' ); return function_exists( 'get_term_meta' ) ? get_term_meta( $term_id, $key, $single ) : get_metadata( 'woocommerce_term', $term_id, $key, $single ); } /*! JSZip v3.10.1 - A JavaScript class for generating and reading zip files (c) 2009-2016 Stuart Knightley Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/main/LICENSE.markdown. JSZip uses the library pako released under the MIT license : https://github.com/nodeca/pako/blob/main/LICENSE */ /** * WooCommerce Stock Functions * * Functions used to manage product stock levels. * * @package WooCommerce\Functions * @version 3.4.0 */ defined( 'ABSPATH' ) || exit; /** * Update a product's stock amount. * * Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues). * * @since 3.0.0 this supports set, increase and decrease. * * @param int|WC_Product $product Product ID or product instance. * @param int|null $stock_quantity Stock quantity. * @param string $operation Type of operation, allows 'set', 'increase' and 'decrease'. * @param bool $updating If true, the product object won't be saved here as it will be updated later. * @return bool|int|null */ function wc_update_product_stock( $product, $stock_quantity = null, $operation = 'set', $updating = false ) { if ( ! is_a( $product, 'WC_Product' ) ) { $product = wc_get_product( $product ); } if ( ! $product ) { return false; } if ( ! is_null( $stock_quantity ) && $product->managing_stock() ) { // Some products (variations) can have their stock managed by their parent. Get the correct object to be updated here. $product_id_with_stock = $product->get_stock_managed_by_id(); $product_with_stock = $product_id_with_stock !== $product->get_id() ? wc_get_product( $product_id_with_stock ) : $product; $data_store = WC_Data_Store::load( 'product' ); // Fire actions to let 3rd parties know the stock is about to be changed. if ( $product_with_stock->is_type( 'variation' ) ) { do_action( 'woocommerce_variation_before_set_stock', $product_with_stock ); } else { do_action( 'woocommerce_product_before_set_stock', $product_with_stock ); } // Update the database. $new_stock = $data_store->update_product_stock( $product_id_with_stock, $stock_quantity, $operation ); // Update the product object. $data_store->read_stock_quantity( $product_with_stock, $new_stock ); // If this is not being called during an update routine, save the product so stock status etc is in sync, and caches are cleared. if ( ! $updating ) { $product_with_stock->save(); } // Fire actions to let 3rd parties know the stock changed. if ( $product_with_stock->is_type( 'variation' ) ) { do_action( 'woocommerce_variation_set_stock', $product_with_stock ); } else { do_action( 'woocommerce_product_set_stock', $product_with_stock ); } return $product_with_stock->get_stock_quantity(); } return $product->get_stock_quantity(); } /** * Update a product's stock status. * * @param int $product_id Product ID. * @param string $status Status. */ function wc_update_product_stock_status( $product_id, $status ) { $product = wc_get_product( $product_id ); if ( $product ) { $product->set_stock_status( $status ); $product->save(); } } /** * When a payment is complete, we can reduce stock levels for items within an order. * * @since 3.0.0 * @param int $order_id Order ID. */ function wc_maybe_reduce_stock_levels( $order_id ) { $order = wc_get_order( $order_id ); if ( ! $order ) { return; } $stock_reduced = $order->get_data_store()->get_stock_reduced( $order_id ); $trigger_reduce = apply_filters( 'woocommerce_payment_complete_reduce_order_stock', ! $stock_reduced, $order_id ); // Only continue if we're reducing stock. if ( ! $trigger_reduce ) { return; } wc_reduce_stock_levels( $order ); // Ensure stock is marked as "reduced" in case payment complete or other stock actions are called. $order->get_data_store()->set_stock_reduced( $order_id, true ); } add_action( 'woocommerce_payment_complete', 'wc_maybe_reduce_stock_levels' ); add_action( 'woocommerce_order_status_completed', 'wc_maybe_reduce_stock_levels' ); add_action( 'woocommerce_order_status_processing', 'wc_maybe_reduce_stock_levels' ); add_action( 'woocommerce_order_status_on-hold', 'wc_maybe_reduce_stock_levels' ); /** * When a payment is cancelled, restore stock. * * @since 3.0.0 * @param int $order_id Order ID. */ function wc_maybe_increase_stock_levels( $order_id ) { $order = wc_get_order( $order_id ); if ( ! $order ) { return; } $stock_reduced = $order->get_data_store()->get_stock_reduced( $order_id ); $trigger_increase = (bool) $stock_reduced; // Only continue if we're increasing stock. if ( ! $trigger_increase ) { return; } wc_increase_stock_levels( $order ); // Ensure stock is not marked as "reduced" anymore. $order->get_data_store()->set_stock_reduced( $order_id, false ); } add_action( 'woocommerce_order_status_cancelled', 'wc_maybe_increase_stock_levels' ); add_action( 'woocommerce_order_status_pending', 'wc_maybe_increase_stock_levels' ); /** * Reduce stock levels for items within an order, if stock has not already been reduced for the items. * * @since 3.0.0 * @param int|WC_Order $order_id Order ID or order instance. */ function wc_reduce_stock_levels( $order_id ) { if ( is_a( $order_id, 'WC_Order' ) ) { $order = $order_id; $order_id = $order->get_id(); } else { $order = wc_get_order( $order_id ); } // We need an order, and a store with stock management to continue. if ( ! $order || 'yes' !== get_option( 'woocommerce_manage_stock' ) || ! apply_filters( 'woocommerce_can_reduce_order_stock', true, $order ) ) { return; } $changes = array(); // Loop over all items. foreach ( $order->get_items() as $item ) { if ( ! $item->is_type( 'line_item' ) ) { continue; } // Only reduce stock once for each item. $product = $item->get_product(); $item_stock_reduced = $item->get_meta( '_reduced_stock', true ); if ( $item_stock_reduced || ! $product || ! $product->managing_stock() ) { continue; } /** * Filter order item quantity. * * @param int|float $quantity Quantity. * @param WC_Order $order Order data. * @param WC_Order_Item_Product $item Order item data. */ $qty = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $order, $item ); $item_name = $product->get_formatted_name(); $new_stock = wc_update_product_stock( $product, $qty, 'decrease' ); if ( is_wp_error( $new_stock ) ) { /* translators: %s item name. */ $order->add_order_note( sprintf( __( 'Unable to reduce stock for item %s.', 'woocommerce' ), $item_name ) ); continue; } $item->add_meta_data( '_reduced_stock', $qty, true ); $item->save(); $change = array( 'product' => $product, 'from' => $new_stock + $qty, 'to' => $new_stock, ); $changes[] = $change; /** * Fires when stock reduced to a specific line item * * @param WC_Order_Item_Product $item Order item data. * @param array $change Change Details. * @param WC_Order $order Order data. * @since 7.6.0 */ do_action( 'woocommerce_reduce_order_item_stock', $item, $change, $order ); } wc_trigger_stock_change_notifications( $order, $changes ); do_action( 'woocommerce_reduce_order_stock', $order ); } /** * After stock change events, triggers emails and adds order notes. * * @since 3.5.0 * @param WC_Order $order order object. * @param array $changes Array of changes. */ function wc_trigger_stock_change_notifications( $order, $changes ) { if ( empty( $changes ) ) { return; } $order_notes = array(); $no_stock_amount = absint( get_option( 'woocommerce_notify_no_stock_amount', 0 ) ); foreach ( $changes as $change ) { $order_notes[] = $change['product']->get_formatted_name() . ' ' . $change['from'] . '→' . $change['to']; $low_stock_amount = absint( wc_get_low_stock_amount( wc_get_product( $change['product']->get_id() ) ) ); if ( $change['to'] <= $no_stock_amount ) { do_action( 'woocommerce_no_stock', wc_get_product( $change['product']->get_id() ) ); } elseif ( $change['to'] <= $low_stock_amount ) { do_action( 'woocommerce_low_stock', wc_get_product( $change['product']->get_id() ) ); } if ( $change['to'] < 0 ) { do_action( 'woocommerce_product_on_backorder', array( 'product' => wc_get_product( $change['product']->get_id() ), 'order_id' => $order->get_id(), 'quantity' => abs( $change['from'] - $change['to'] ), ) ); } } $order->add_order_note( __( 'Stock levels reduced:', 'woocommerce' ) . ' ' . implode( ', ', $order_notes ) ); } /** * Increase stock levels for items within an order. * * @since 3.0.0 * @param int|WC_Order $order_id Order ID or order instance. */ function wc_increase_stock_levels( $order_id ) { if ( is_a( $order_id, 'WC_Order' ) ) { $order = $order_id; $order_id = $order->get_id(); } else { $order = wc_get_order( $order_id ); } // We need an order, and a store with stock management to continue. if ( ! $order || 'yes' !== get_option( 'woocommerce_manage_stock' ) || ! apply_filters( 'woocommerce_can_restore_order_stock', true, $order ) ) { return; } $changes = array(); // Loop over all items. foreach ( $order->get_items() as $item ) { if ( ! $item->is_type( 'line_item' ) ) { continue; } // Only increase stock once for each item. $product = $item->get_product(); $item_stock_reduced = $item->get_meta( '_reduced_stock', true ); if ( ! $item_stock_reduced || ! $product || ! $product->managing_stock() ) { continue; } $item_name = $product->get_formatted_name(); $new_stock = wc_update_product_stock( $product, $item_stock_reduced, 'increase' ); if ( is_wp_error( $new_stock ) ) { /* translators: %s item name. */ $order->add_order_note( sprintf( __( 'Unable to restore stock for item %s.', 'woocommerce' ), $item_name ) ); continue; } $item->delete_meta_data( '_reduced_stock' ); $item->save(); $changes[] = $item_name . ' ' . ( $new_stock - $item_stock_reduced ) . '→' . $new_stock; } if ( $changes ) { $order->add_order_note( __( 'Stock levels increased:', 'woocommerce' ) . ' ' . implode( ', ', $changes ) ); } do_action( 'woocommerce_restore_order_stock', $order ); } /** * See how much stock is being held in pending orders. * * @since 3.5.0 * @param WC_Product $product Product to check. * @param integer $exclude_order_id Order ID to exclude. * @return int */ function wc_get_held_stock_quantity( WC_Product $product, $exclude_order_id = 0 ) { /** * Filter: woocommerce_hold_stock_for_checkout * Allows enable/disable hold stock functionality on checkout. * * @since 4.3.0 * @param bool $enabled Default to true if managing stock globally. */ if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', wc_string_to_bool( get_option( 'woocommerce_manage_stock', 'yes' ) ) ) ) { return 0; } return ( new \Automattic\WooCommerce\Checkout\Helpers\ReserveStock() )->get_reserved_stock( $product, $exclude_order_id ); } /** * Hold stock for an order. * * @throws ReserveStockException If reserve stock fails. * * @since 4.1.0 * @param \WC_Order|int $order Order ID or instance. */ function wc_reserve_stock_for_order( $order ) { /** * Filter: woocommerce_hold_stock_for_checkout * Allows enable/disable hold stock functionality on checkout. * * @since @since 4.1.0 * @param bool $enabled Default to true if managing stock globally. */ if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', wc_string_to_bool( get_option( 'woocommerce_manage_stock', 'yes' ) ) ) ) { return; } $order = $order instanceof WC_Order ? $order : wc_get_order( $order ); if ( $order ) { ( new \Automattic\WooCommerce\Checkout\Helpers\ReserveStock() )->reserve_stock_for_order( $order ); } } add_action( 'woocommerce_checkout_order_created', 'wc_reserve_stock_for_order' ); /** * Release held stock for an order. * * @since 4.3.0 * @param \WC_Order|int $order Order ID or instance. */ function wc_release_stock_for_order( $order ) { /** * Filter: woocommerce_hold_stock_for_checkout * Allows enable/disable hold stock functionality on checkout. * * @since 4.3.0 * @param bool $enabled Default to true if managing stock globally. */ if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', wc_string_to_bool( get_option( 'woocommerce_manage_stock', 'yes' ) ) ) ) { return; } $order = $order instanceof WC_Order ? $order : wc_get_order( $order ); if ( $order ) { ( new \Automattic\WooCommerce\Checkout\Helpers\ReserveStock() )->release_stock_for_order( $order ); } } add_action( 'woocommerce_checkout_order_exception', 'wc_release_stock_for_order' ); add_action( 'woocommerce_payment_complete', 'wc_release_stock_for_order', 11 ); add_action( 'woocommerce_order_status_cancelled', 'wc_release_stock_for_order', 11 ); add_action( 'woocommerce_order_status_completed', 'wc_release_stock_for_order', 11 ); add_action( 'woocommerce_order_status_processing', 'wc_release_stock_for_order', 11 ); add_action( 'woocommerce_order_status_on-hold', 'wc_release_stock_for_order', 11 ); /** * Return low stock amount to determine if notification needs to be sent * * Since 5.2.0, this function no longer redirects from variation to its parent product. * Low stock amount can now be attached to the variation itself and if it isn't, only * then we check the parent product, and if it's not there, then we take the default * from the store-wide setting. * * @param WC_Product $product Product to get data from. * @since 3.5.0 * @return int */ function wc_get_low_stock_amount( WC_Product $product ) { $low_stock_amount = $product->get_low_stock_amount(); if ( '' === $low_stock_amount && $product->is_type( 'variation' ) ) { $product = wc_get_product( $product->get_parent_id() ); $low_stock_amount = $product->get_low_stock_amount(); } if ( '' === $low_stock_amount ) { $low_stock_amount = get_option( 'woocommerce_notify_low_stock_amount', 2 ); } return (int) $low_stock_amount; } /** * WooCommerce Terms * * Functions for handling terms/term meta. * * @package WooCommerce\Functions * @version 2.1.0 */ defined( 'ABSPATH' ) || exit; /** * Change get terms defaults for attributes to order by the sorting setting, or default to menu_order for sortable taxonomies. * * @since 3.6.0 Sorting options are now set as the default automatically, so you no longer have to request to orderby menu_order. * * @param array $defaults An array of default get_terms() arguments. * @param array $taxonomies An array of taxonomies. * @return array */ function wc_change_get_terms_defaults( $defaults, $taxonomies ) { if ( is_array( $taxonomies ) && 1 < count( $taxonomies ) ) { return $defaults; } $taxonomy = is_array( $taxonomies ) ? (string) current( $taxonomies ) : $taxonomies; $orderby = 'name'; if ( taxonomy_is_product_attribute( $taxonomy ) ) { $orderby = wc_attribute_orderby( $taxonomy ); } elseif ( in_array( $taxonomy, apply_filters( 'woocommerce_sortable_taxonomies', array( 'product_cat' ) ), true ) ) { $orderby = 'menu_order'; } // Change defaults. Invalid values will be changed later @see wc_change_pre_get_terms. // These are in place so we know if a specific order was requested. switch ( $orderby ) { case 'menu_order': case 'name_num': case 'parent': $defaults['orderby'] = $orderby; break; } return $defaults; } add_filter( 'get_terms_defaults', 'wc_change_get_terms_defaults', 10, 2 ); /** * Adds support to get_terms for menu_order argument. * * @since 3.6.0 * @param WP_Term_Query $terms_query Instance of WP_Term_Query. */ function wc_change_pre_get_terms( $terms_query ) { $args = &$terms_query->query_vars; // Put back valid orderby values. if ( 'menu_order' === $args['orderby'] ) { $args['orderby'] = 'name'; $args['force_menu_order_sort'] = true; } if ( 'name_num' === $args['orderby'] ) { $args['orderby'] = 'name'; $args['force_numeric_name'] = true; } // When COUNTING, disable custom sorting. if ( 'count' === $args['fields'] ) { return; } // Support menu_order arg used in previous versions. if ( ! empty( $args['menu_order'] ) ) { $args['order'] = 'DESC' === strtoupper( $args['menu_order'] ) ? 'DESC' : 'ASC'; $args['force_menu_order_sort'] = true; } if ( ! empty( $args['force_menu_order_sort'] ) ) { $args['orderby'] = 'meta_value_num'; $args['meta_key'] = 'order'; // phpcs:ignore $terms_query->meta_query->parse_query_vars( $args ); } } add_action( 'pre_get_terms', 'wc_change_pre_get_terms', 10, 1 ); /** * Adjust term query to handle custom sorting parameters. * * @param array $clauses Clauses. * @param array $taxonomies Taxonomies. * @param array $args Arguments. * @return array */ function wc_terms_clauses( $clauses, $taxonomies, $args ) { global $wpdb; // No need to filter when counting. if ( strpos( $clauses['fields'], 'COUNT(*)' ) !== false ) { return $clauses; } // Force numeric sort if using name_num custom sorting param. if ( ! empty( $args['force_numeric_name'] ) ) { $clauses['orderby'] = str_replace( 'ORDER BY t.name', 'ORDER BY t.name+0', $clauses['orderby'] ); } // For sorting, force left join in case order meta is missing. if ( ! empty( $args['force_menu_order_sort'] ) ) { $clauses['join'] = str_replace( "INNER JOIN {$wpdb->termmeta} ON ( t.term_id = {$wpdb->termmeta}.term_id )", "LEFT JOIN {$wpdb->termmeta} ON ( t.term_id = {$wpdb->termmeta}.term_id AND {$wpdb->termmeta}.meta_key='order')", $clauses['join'] ); $clauses['where'] = str_replace( "{$wpdb->termmeta}.meta_key = 'order'", "( {$wpdb->termmeta}.meta_key = 'order' OR {$wpdb->termmeta}.meta_key IS NULL )", $clauses['where'] ); $clauses['orderby'] = 'DESC' === $args['order'] ? str_replace( 'meta_value+0', 'meta_value+0 DESC, t.name', $clauses['orderby'] ) : str_replace( 'meta_value+0', 'meta_value+0 ASC, t.name', $clauses['orderby'] ); } return $clauses; } add_filter( 'terms_clauses', 'wc_terms_clauses', 99, 3 ); /** * Helper to get cached object terms and filter by field using wp_list_pluck(). * Works as a cached alternative for wp_get_post_terms() and wp_get_object_terms(). * * @since 3.0.0 * @param int $object_id Object ID. * @param string $taxonomy Taxonomy slug. * @param string $field Field name. * @param string $index_key Index key name. * @return array */ function wc_get_object_terms( $object_id, $taxonomy, $field = null, $index_key = null ) { // Test if terms exists. get_the_terms() return false when it finds no terms. $terms = get_the_terms( $object_id, $taxonomy ); if ( ! $terms || is_wp_error( $terms ) ) { return array(); } return is_null( $field ) ? $terms : wp_list_pluck( $terms, $field, $index_key ); } /** * Cached version of wp_get_post_terms(). * This is a private function (internal use ONLY). * * @since 3.0.0 * @param int $product_id Product ID. * @param string $taxonomy Taxonomy slug. * @param array $args Query arguments. * @return array */ function _wc_get_cached_product_terms( $product_id, $taxonomy, $args = array() ) { $cache_key = 'wc_' . $taxonomy . md5( wp_json_encode( $args ) ); $cache_group = WC_Cache_Helper::get_cache_prefix( 'product_' . $product_id ) . $product_id; $terms = wp_cache_get( $cache_key, $cache_group ); if ( false !== $terms ) { return $terms; } $terms = wp_get_post_terms( $product_id, $taxonomy, $args ); wp_cache_add( $cache_key, $terms, $cache_group ); return $terms; } /** * Wrapper used to get terms for a product. * * @param int $product_id Product ID. * @param string $taxonomy Taxonomy slug. * @param array $args Query arguments. * @return array */ function wc_get_product_terms( $product_id, $taxonomy, $args = array() ) { if ( ! taxonomy_exists( $taxonomy ) ) { return array(); } return apply_filters( 'woocommerce_get_product_terms', _wc_get_cached_product_terms( $product_id, $taxonomy, $args ), $product_id, $taxonomy, $args ); } /** * Sort by name (numeric). * * @param WP_Post $a First item to compare. * @param WP_Post $b Second item to compare. * @return int */ function _wc_get_product_terms_name_num_usort_callback( $a, $b ) { $a_name = (float) $a->name; $b_name = (float) $b->name; if ( abs( $a_name - $b_name ) < 0.001 ) { return 0; } return ( $a_name < $b_name ) ? -1 : 1; } /** * Sort by parent. * * @param WP_Post $a First item to compare. * @param WP_Post $b Second item to compare. * @return int */ function _wc_get_product_terms_parent_usort_callback( $a, $b ) { if ( $a->parent === $b->parent ) { return 0; } return ( $a->parent < $b->parent ) ? 1 : -1; } /** * WooCommerce Dropdown categories. * * @param array $args Args to control display of dropdown. */ function wc_product_dropdown_categories( $args = array() ) { global $wp_query; $args = wp_parse_args( $args, array( 'pad_counts' => 1, 'show_count' => 1, 'hierarchical' => 1, 'hide_empty' => 1, 'show_uncategorized' => 1, 'orderby' => 'name', 'selected' => isset( $wp_query->query_vars['product_cat'] ) ? $wp_query->query_vars['product_cat'] : '', 'show_option_none' => __( 'Select a category', 'woocommerce' ), 'option_none_value' => '', 'value_field' => 'slug', 'taxonomy' => 'product_cat', 'name' => 'product_cat', 'class' => 'dropdown_product_cat', ) ); if ( 'order' === $args['orderby'] ) { $args['orderby'] = 'meta_value_num'; $args['meta_key'] = 'order'; // phpcs:ignore } wp_dropdown_categories( $args ); } /** * Custom walker for Product Categories. * * Previously used by wc_product_dropdown_categories, but wp_dropdown_categories has been fixed in core. * * @param mixed ...$args Variable number of parameters to be passed to the walker. * @return mixed */ function wc_walk_category_dropdown_tree( ...$args ) { if ( ! class_exists( 'WC_Product_Cat_Dropdown_Walker', false ) ) { include_once WC()->plugin_path() . '/includes/walkers/class-wc-product-cat-dropdown-walker.php'; } // The user's options are the third parameter. if ( empty( $args[2]['walker'] ) || ! is_a( $args[2]['walker'], 'Walker' ) ) { $walker = new WC_Product_Cat_Dropdown_Walker(); } else { $walker = $args[2]['walker']; } return $walker->walk( ...$args ); } /** * Migrate data from WC term meta to WP term meta. * * When the database is updated to support term meta, migrate WC term meta data across. * We do this when the new version is >= 34370, and the old version is < 34370 (34370 is when term meta table was added). * * @param string $wp_db_version The new $wp_db_version. * @param string $wp_current_db_version The old (current) $wp_db_version. */ function wc_taxonomy_metadata_migrate_data( $wp_db_version, $wp_current_db_version ) { if ( $wp_db_version >= 34370 && $wp_current_db_version < 34370 ) { global $wpdb; if ( $wpdb->query( "INSERT INTO {$wpdb->termmeta} ( term_id, meta_key, meta_value ) SELECT woocommerce_term_id, meta_key, meta_value FROM {$wpdb->prefix}woocommerce_termmeta;" ) ) { $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}woocommerce_termmeta" ); } } } add_action( 'wp_upgrade', 'wc_taxonomy_metadata_migrate_data', 10, 2 ); /** * Move a term before the a given element of its hierarchy level. * * @param int $the_term Term ID. * @param int $next_id The id of the next sibling element in save hierarchy level. * @param string $taxonomy Taxnomy. * @param int $index Term index (default: 0). * @param mixed $terms List of terms. (default: null). * @return int */ function wc_reorder_terms( $the_term, $next_id, $taxonomy, $index = 0, $terms = null ) { if ( ! $terms ) { $terms = get_terms( $taxonomy, 'hide_empty=0&parent=0&menu_order=ASC' ); } if ( empty( $terms ) ) { return $index; } $id = intval( $the_term->term_id ); $term_in_level = false; // Flag: is our term to order in this level of terms. foreach ( $terms as $term ) { $term_id = intval( $term->term_id ); if ( $term_id === $id ) { // Our term to order, we skip. $term_in_level = true; continue; // Our term to order, we skip. } // the nextid of our term to order, lets move our term here. if ( null !== $next_id && $term_id === $next_id ) { $index++; $index = wc_set_term_order( $id, $index, $taxonomy, true ); } // Set order. $index++; $index = wc_set_term_order( $term_id, $index, $taxonomy ); /** * After a term has had it's order set. */ do_action( 'woocommerce_after_set_term_order', $term, $index, $taxonomy ); // If that term has children we walk through them. $children = get_terms( $taxonomy, "parent={$term_id}&hide_empty=0&menu_order=ASC" ); if ( ! empty( $children ) ) { $index = wc_reorder_terms( $the_term, $next_id, $taxonomy, $index, $children ); } } // No nextid meaning our term is in last position. if ( $term_in_level && null === $next_id ) { $index = wc_set_term_order( $id, $index + 1, $taxonomy, true ); } return $index; } /** * Set the sort order of a term. * * @param int $term_id Term ID. * @param int $index Index. * @param string $taxonomy Taxonomy. * @param bool $recursive Recursive (default: false). * @return int */ function wc_set_term_order( $term_id, $index, $taxonomy, $recursive = false ) { $term_id = (int) $term_id; $index = (int) $index; update_term_meta( $term_id, 'order', $index ); if ( ! $recursive ) { return $index; } $children = get_terms( $taxonomy, "parent=$term_id&hide_empty=0&menu_order=ASC" ); foreach ( $children as $term ) { $index++; $index = wc_set_term_order( $term->term_id, $index, $taxonomy, true ); } clean_term_cache( $term_id, $taxonomy ); return $index; } /** * Function for recounting product terms, ignoring hidden products. * * @param array $terms List of terms. * @param object $taxonomy Taxonomy. * @param bool $callback Callback. * @param bool $terms_are_term_taxonomy_ids If terms are from term_taxonomy_id column. */ function _wc_term_recount( $terms, $taxonomy, $callback = true, $terms_are_term_taxonomy_ids = true ) { global $wpdb; /** * Filter to allow/prevent recounting of terms as it could be expensive. * A likely scenario for this is when bulk importing products. We could * then prevent it from recounting per product but instead recount it once * when import is done. Of course this means the import logic has to support this. * * @since 5.2 * @param bool */ if ( ! apply_filters( 'woocommerce_product_recount_terms', true ) ) { return; } // Standard callback. if ( $callback ) { _update_post_term_count( $terms, $taxonomy ); } $exclude_term_ids = array(); $product_visibility_term_ids = wc_get_product_visibility_term_ids(); if ( $product_visibility_term_ids['exclude-from-catalog'] ) { $exclude_term_ids[] = $product_visibility_term_ids['exclude-from-catalog']; } if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && $product_visibility_term_ids['outofstock'] ) { $exclude_term_ids[] = $product_visibility_term_ids['outofstock']; } $query = array( 'fields' => " SELECT COUNT( DISTINCT ID ) FROM {$wpdb->posts} p ", 'join' => '', 'where' => " WHERE 1=1 AND p.post_status = 'publish' AND p.post_type = 'product' ", ); if ( count( $exclude_term_ids ) ) { $query['join'] .= " LEFT JOIN ( SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ( " . implode( ',', array_map( 'absint', $exclude_term_ids ) ) . ' ) ) AS exclude_join ON exclude_join.object_id = p.ID'; $query['where'] .= ' AND exclude_join.object_id IS NULL'; } // Pre-process term taxonomy ids. if ( ! $terms_are_term_taxonomy_ids ) { // We passed in an array of TERMS in format id=>parent. $terms = array_filter( (array) array_keys( $terms ) ); } else { // If we have term taxonomy IDs we need to get the term ID. $term_taxonomy_ids = $terms; $terms = array(); foreach ( $term_taxonomy_ids as $term_taxonomy_id ) { $term = get_term_by( 'term_taxonomy_id', $term_taxonomy_id, $taxonomy->name ); $terms[] = $term->term_id; } } // Exit if we have no terms to count. if ( empty( $terms ) ) { return; } // Ancestors need counting. if ( is_taxonomy_hierarchical( $taxonomy->name ) ) { foreach ( $terms as $term_id ) { $terms = array_merge( $terms, get_ancestors( $term_id, $taxonomy->name ) ); } } // Unique terms only. $terms = array_unique( $terms ); // Count the terms. foreach ( $terms as $term_id ) { $terms_to_count = array( absint( $term_id ) ); if ( is_taxonomy_hierarchical( $taxonomy->name ) ) { // We need to get the $term's hierarchy so we can count its children too. $children = get_term_children( $term_id, $taxonomy->name ); if ( $children && ! is_wp_error( $children ) ) { $terms_to_count = array_unique( array_map( 'absint', array_merge( $terms_to_count, $children ) ) ); } } // Generate term query. $term_query = $query; $term_query['join'] .= " INNER JOIN ( SELECT object_id FROM {$wpdb->term_relationships} INNER JOIN {$wpdb->term_taxonomy} using( term_taxonomy_id ) WHERE term_id IN ( " . implode( ',', array_map( 'absint', $terms_to_count ) ) . ' ) ) AS include_join ON include_join.object_id = p.ID'; // Get the count. // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $count = $wpdb->get_var( implode( ' ', $term_query ) ); // Update the count. update_term_meta( $term_id, 'product_count_' . $taxonomy->name, absint( $count ) ); } delete_transient( 'wc_term_counts' ); } /** * Recount terms after the stock amount changes. * * @param int $product_id Product ID. */ function wc_recount_after_stock_change( $product_id ) { if ( 'yes' !== get_option( 'woocommerce_hide_out_of_stock_items' ) ) { return; } _wc_recount_terms_by_product( $product_id ); } add_action( 'woocommerce_product_set_stock_status', 'wc_recount_after_stock_change' ); /** * Overrides the original term count for product categories and tags with the product count. * that takes catalog visibility into account. * * @param array $terms List of terms. * @param string|array $taxonomies Single taxonomy or list of taxonomies. * @return array */ function wc_change_term_counts( $terms, $taxonomies ) { if ( is_admin() || wp_doing_ajax() ) { return $terms; } if ( ! isset( $taxonomies[0] ) || ! in_array( $taxonomies[0], apply_filters( 'woocommerce_change_term_counts', array( 'product_cat', 'product_tag' ) ), true ) ) { return $terms; } $o_term_counts = get_transient( 'wc_term_counts' ); $term_counts = false === $o_term_counts ? array() : $o_term_counts; foreach ( $terms as &$term ) { if ( is_object( $term ) ) { $term_counts[ $term->term_id ] = isset( $term_counts[ $term->term_id ] ) ? $term_counts[ $term->term_id ] : get_term_meta( $term->term_id, 'product_count_' . $taxonomies[0], true ); if ( '' !== $term_counts[ $term->term_id ] ) { $term->count = absint( $term_counts[ $term->term_id ] ); } } } // Update transient. if ( $term_counts !== $o_term_counts ) { set_transient( 'wc_term_counts', $term_counts, DAY_IN_SECONDS * 30 ); } return $terms; } add_filter( 'get_terms', 'wc_change_term_counts', 10, 2 ); /** * Return products in a given term, and cache value. * * To keep in sync, product_count will be cleared on "set_object_terms". * * @param int $term_id Term ID. * @param string $taxonomy Taxonomy. * @return array */ function wc_get_term_product_ids( $term_id, $taxonomy ) { $product_ids = get_term_meta( $term_id, 'product_ids', true ); if ( false === $product_ids || ! is_array( $product_ids ) ) { $product_ids = get_objects_in_term( $term_id, $taxonomy ); update_term_meta( $term_id, 'product_ids', $product_ids ); } return $product_ids; } /** * When a post is updated and terms recounted (called by _update_post_term_count), clear the ids. * * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. */ function wc_clear_term_product_ids( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) { foreach ( $old_tt_ids as $term_id ) { delete_term_meta( $term_id, 'product_ids' ); } foreach ( $tt_ids as $term_id ) { delete_term_meta( $term_id, 'product_ids' ); } } add_action( 'set_object_terms', 'wc_clear_term_product_ids', 10, 6 ); /** * Get full list of product visibilty term ids. * * @since 3.0.0 * @return int[] */ function wc_get_product_visibility_term_ids() { if ( ! taxonomy_exists( 'product_visibility' ) ) { wc_doing_it_wrong( __FUNCTION__, 'wc_get_product_visibility_term_ids should not be called before taxonomies are registered (woocommerce_after_register_post_type action).', '3.1' ); return array(); } return array_map( 'absint', wp_parse_args( wp_list_pluck( get_terms( array( 'taxonomy' => 'product_visibility', 'hide_empty' => false, ) ), 'term_taxonomy_id', 'name' ), array( 'exclude-from-catalog' => 0, 'exclude-from-search' => 0, 'featured' => 0, 'outofstock' => 0, 'rated-1' => 0, 'rated-2' => 0, 'rated-3' => 0, 'rated-4' => 0, 'rated-5' => 0, ) ) ); } /** * Recounts all terms. * * @since 5.2 * @return void */ function wc_recount_all_terms() { $product_cats = get_terms( 'product_cat', array( 'hide_empty' => false, 'fields' => 'id=>parent', ) ); _wc_term_recount( $product_cats, get_taxonomy( 'product_cat' ), true, false ); $product_tags = get_terms( 'product_tag', array( 'hide_empty' => false, 'fields' => 'id=>parent', ) ); _wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), true, false ); } /** * Recounts terms by product. * * @since 5.2 * @param int $product_id The ID of the product. * @return void */ function _wc_recount_terms_by_product( $product_id = '' ) { if ( empty( $product_id ) ) { return; } $product_terms = get_the_terms( $product_id, 'product_cat' ); if ( $product_terms ) { $product_cats = array(); foreach ( $product_terms as $term ) { $product_cats[ $term->term_id ] = $term->parent; } _wc_term_recount( $product_cats, get_taxonomy( 'product_cat' ), false, false ); } $product_terms = get_the_terms( $product_id, 'product_tag' ); if ( $product_terms ) { $product_tags = array(); foreach ( $product_terms as $term ) { $product_tags[ $term->term_id ] = $term->parent; } _wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), false, false ); } } /*! pro-elements - v3.23.0 - 23-07-2024 */ body.e-off-canvas__no-scroll,body.e-off-canvas__no-scroll-animation{overflow:hidden}.elementor-widget-off-canvas{height:-moz-fit-content;height:fit-content;--e-off-canvas-width:400px;--e-off-canvas-height:100vh;--e-off-canvas-justify-content:flex-start;--e-off-canvas-align-items:flex-start;--e-off-canvas-animation-duration:1.5s;--e-off-canvas-content-overflow:auto;--e-off-canvas-overlay-opacity:1;--e-off-canvas-animation-duration-minimum:Max(0.001s,var(--e-off-canvas-animation-duration))}.elementor-widget-off-canvas .e-off-canvas{width:100%;height:100%;top:0;left:0;z-index:2147483630;position:fixed;pointer-events:none}.elementor-widget-off-canvas .e-off-canvas[aria-hidden=true]{visibility:hidden;opacity:0}.elementor-widget-off-canvas .e-off-canvas[aria-hidden=true] .elementor-add-section{display:none}.elementor-widget-off-canvas .e-off-canvas__overlay{background-color:rgba(0,0,0,.5);width:100%;height:100%;top:0;left:0;position:absolute;pointer-events:all;opacity:var(--e-off-canvas-overlay-opacity);transition:0s}.elementor-widget-off-canvas .e-off-canvas__overlay.no-pointer-events{pointer-events:none}.elementor-widget-off-canvas .e-off-canvas__main{display:flex;justify-content:var(--e-off-canvas-justify-content);align-items:var(--e-off-canvas-align-items);width:100%;height:100%;top:0;left:0;position:absolute}.elementor-widget-off-canvas .e-off-canvas__main.animated{animation-duration:var(--e-off-canvas-animation-duration-minimum)}.elementor-widget-off-canvas .e-off-canvas__main.animated.none{opacity:1;visibility:visible;animation:e-off-canvas-without-animation 1ms}.elementor-widget-off-canvas .e-off-canvas__main.animated.none.reversed{opacity:0;visibility:hidden}.elementor-widget-off-canvas .e-off-canvas__content{background-color:#fff;box-shadow:2px 8px 23px 3px rgba(0,0,0,.2);width:var(--e-off-canvas-width);height:var(--e-off-canvas-height);pointer-events:all;overflow:var(--e-off-canvas-content-overflow)}.elementor-widget-off-canvas .animated-reverse-wrapper{visibility:hidden;opacity:0;transform:none}.elementor-widget-off-canvas .animated-reverse-wrapper:not(.no-animation){animation:e-off-canvas-close var(--e-off-canvas-animation-duration-minimum)}.elementor-widget-off-canvas .animated-reverse-wrapper .no-animation{animation:e-off-canvas-close 1ms}@keyframes e-off-canvas-close{0%,99.99%{visibility:visible;opacity:1}to{visibility:hidden;opacity:0;transform:none}}@keyframes e-off-canvas-without-animation{0%{visibility:hidden;opacity:0}to{visibility:visible;opacity:1}}/** * WooCommerce Cart Functions * * Functions for cart specific things. * * @package WooCommerce\Functions * @version 2.5.0 */ use Automattic\Jetpack\Constants; defined( 'ABSPATH' ) || exit; /** * Prevent password protected products being added to the cart. * * @param bool $passed Validation. * @param int $product_id Product ID. * @return bool */ function wc_protected_product_add_to_cart( $passed, $product_id ) { if ( post_password_required( $product_id ) ) { $passed = false; wc_add_notice( __( 'This product is protected and cannot be purchased.', 'woocommerce' ), 'error' ); } return $passed; } add_filter( 'woocommerce_add_to_cart_validation', 'wc_protected_product_add_to_cart', 10, 2 ); /** * Clears the cart session when called. */ function wc_empty_cart() { if ( ! isset( WC()->cart ) || '' === WC()->cart ) { WC()->cart = new WC_Cart(); } WC()->cart->empty_cart( false ); } /** * Load the persistent cart. * * @param string $user_login User login. * @param WP_User $user User data. * @deprecated 2.3 */ function wc_load_persistent_cart( $user_login, $user ) { if ( ! $user || ! apply_filters( 'woocommerce_persistent_cart_enabled', true ) ) { return; } $saved_cart = get_user_meta( $user->ID, '_woocommerce_persistent_cart_' . get_current_blog_id(), true ); if ( ! $saved_cart ) { return; } $cart = WC()->session->cart; if ( empty( $cart ) || ! is_array( $cart ) || 0 === count( $cart ) ) { WC()->session->cart = $saved_cart['cart']; } } /** * Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer. * * Do not use for redirects, use {@see wp_get_referer()} instead. * * @since 2.6.1 * @return string|false Referer URL on success, false on failure. */ function wc_get_raw_referer() { if ( function_exists( 'wp_get_raw_referer' ) ) { return wp_get_raw_referer(); } if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) { // WPCS: input var ok, CSRF ok. return wp_unslash( $_REQUEST['_wp_http_referer'] ); // WPCS: input var ok, CSRF ok, sanitization ok. } elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) ) { // WPCS: input var ok, CSRF ok. return wp_unslash( $_SERVER['HTTP_REFERER'] ); // WPCS: input var ok, CSRF ok, sanitization ok. } return false; } /** * Add to cart messages. * * @param int|array $products Product ID list or single product ID. * @param bool $show_qty Should quantities be shown? Added in 2.6.0. * @param bool $return Return message rather than add it. * * @return mixed */ function wc_add_to_cart_message( $products, $show_qty = false, $return = false ) { $titles = array(); $count = 0; if ( ! is_array( $products ) ) { $products = array( $products => 1 ); $show_qty = false; } if ( ! $show_qty ) { $products = array_fill_keys( array_keys( $products ), 1 ); } foreach ( $products as $product_id => $qty ) { /* translators: %s: product name */ $titles[] = apply_filters( 'woocommerce_add_to_cart_qty_html', ( $qty > 1 ? absint( $qty ) . ' × ' : '' ), $product_id ) . apply_filters( 'woocommerce_add_to_cart_item_name_in_quotes', sprintf( _x( '“%s”', 'Item name in quotes', 'woocommerce' ), strip_tags( get_the_title( $product_id ) ) ), $product_id ); $count += $qty; } $titles = array_filter( $titles ); /* translators: %s: product name */ $added_text = sprintf( _n( '%s has been added to your cart.', '%s have been added to your cart.', $count, 'woocommerce' ), wc_format_list_of_items( $titles ) ); // Output success messages. $wp_button_class = wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : ''; if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) { $return_to = apply_filters( 'woocommerce_continue_shopping_redirect', wc_get_raw_referer() ? wp_validate_redirect( wc_get_raw_referer(), false ) : wc_get_page_permalink( 'shop' ) ); $message = sprintf( '%s %s', esc_url( $return_to ), esc_attr( $wp_button_class ), esc_html__( 'Continue shopping', 'woocommerce' ), esc_html( $added_text ) ); } else { $message = sprintf( '%s %s', esc_url( wc_get_cart_url() ), esc_attr( $wp_button_class ), esc_html__( 'View cart', 'woocommerce' ), esc_html( $added_text ) ); } if ( has_filter( 'wc_add_to_cart_message' ) ) { wc_deprecated_function( 'The wc_add_to_cart_message filter', '3.0', 'wc_add_to_cart_message_html' ); $message = apply_filters( 'wc_add_to_cart_message', $message, $product_id ); } $message = apply_filters( 'wc_add_to_cart_message_html', $message, $products, $show_qty ); if ( $return ) { return $message; } else { wc_add_notice( $message, apply_filters( 'woocommerce_add_to_cart_notice_type', 'success' ) ); } } /** * Comma separate a list of item names, and replace final comma with 'and'. * * @param array $items Cart items. * @return string */ function wc_format_list_of_items( $items ) { $item_string = ''; foreach ( $items as $key => $item ) { $item_string .= $item; if ( count( $items ) === $key + 2 ) { $item_string .= ' ' . __( 'and', 'woocommerce' ) . ' '; } elseif ( count( $items ) !== $key + 1 ) { $item_string .= ', '; } } return $item_string; } /** * Clear cart after payment. */ function wc_clear_cart_after_payment() { global $wp; if ( ! empty( $wp->query_vars['order-received'] ) ) { $order_id = absint( $wp->query_vars['order-received'] ); $order_key = isset( $_GET['key'] ) ? wc_clean( wp_unslash( $_GET['key'] ) ) : ''; // WPCS: input var ok, CSRF ok. if ( $order_id > 0 ) { $order = wc_get_order( $order_id ); if ( $order && hash_equals( $order->get_order_key(), $order_key ) ) { WC()->cart->empty_cart(); } } } if ( WC()->session->order_awaiting_payment > 0 ) { $order = wc_get_order( WC()->session->order_awaiting_payment ); if ( $order && $order->get_id() > 0 ) { // If the order has not failed, or is not pending, the order must have gone through. if ( ! $order->has_status( array( 'failed', 'pending', 'cancelled' ) ) ) { WC()->cart->empty_cart(); } } } } add_action( 'template_redirect', 'wc_clear_cart_after_payment', 20 ); /** * Get the subtotal. */ function wc_cart_totals_subtotal_html() { echo WC()->cart->get_cart_subtotal(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** * Get shipping methods. */ function wc_cart_totals_shipping_html() { $packages = WC()->shipping()->get_packages(); $first = true; foreach ( $packages as $i => $package ) { $chosen_method = isset( WC()->session->chosen_shipping_methods[ $i ] ) ? WC()->session->chosen_shipping_methods[ $i ] : ''; $product_names = array(); if ( count( $packages ) > 1 ) { foreach ( $package['contents'] as $item_id => $values ) { $product_names[ $item_id ] = $values['data']->get_name() . ' ×' . $values['quantity']; } $product_names = apply_filters( 'woocommerce_shipping_package_details_array', $product_names, $package ); } wc_get_template( 'cart/cart-shipping.php', array( 'package' => $package, 'available_methods' => $package['rates'], 'show_package_details' => count( $packages ) > 1, 'show_shipping_calculator' => is_cart() && apply_filters( 'woocommerce_shipping_show_shipping_calculator', $first, $i, $package ), 'package_details' => implode( ', ', $product_names ), /* translators: %d: shipping package number */ 'package_name' => apply_filters( 'woocommerce_shipping_package_name', ( ( $i + 1 ) > 1 ) ? sprintf( _x( 'Shipping %d', 'shipping packages', 'woocommerce' ), ( $i + 1 ) ) : _x( 'Shipping', 'shipping packages', 'woocommerce' ), $i, $package ), 'index' => $i, 'chosen_method' => $chosen_method, 'formatted_destination' => WC()->countries->get_formatted_address( $package['destination'], ', ' ), 'has_calculated_shipping' => WC()->customer->has_calculated_shipping(), ) ); $first = false; } } /** * Get taxes total. */ function wc_cart_totals_taxes_total_html() { echo apply_filters( 'woocommerce_cart_totals_taxes_total_html', wc_price( WC()->cart->get_taxes_total() ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** * Get a coupon label. * * @param string|WC_Coupon $coupon Coupon data or code. * @param bool $echo Echo or return. * * @return string */ function wc_cart_totals_coupon_label( $coupon, $echo = true ) { if ( is_string( $coupon ) ) { $coupon = new WC_Coupon( $coupon ); } /* translators: %s: coupon code */ $label = apply_filters( 'woocommerce_cart_totals_coupon_label', sprintf( esc_html__( 'Coupon: %s', 'woocommerce' ), $coupon->get_code() ), $coupon ); if ( $echo ) { echo $label; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } else { return $label; } } /** * Get coupon display HTML. * * @param string|WC_Coupon $coupon Coupon data or code. */ function wc_cart_totals_coupon_html( $coupon ) { if ( is_string( $coupon ) ) { $coupon = new WC_Coupon( $coupon ); } $discount_amount_html = ''; $amount = WC()->cart->get_coupon_discount_amount( $coupon->get_code(), WC()->cart->display_cart_ex_tax ); $discount_amount_html = '-' . wc_price( $amount ); if ( $coupon->get_free_shipping() && empty( $amount ) ) { $discount_amount_html = __( 'Free shipping coupon', 'woocommerce' ); } $discount_amount_html = apply_filters( 'woocommerce_coupon_discount_amount_html', $discount_amount_html, $coupon ); $coupon_html = $discount_amount_html . ' ' . __( '[Remove]', 'woocommerce' ) . ''; echo wp_kses( apply_filters( 'woocommerce_cart_totals_coupon_html', $coupon_html, $coupon, $discount_amount_html ), array_replace_recursive( wp_kses_allowed_html( 'post' ), array( 'a' => array( 'data-coupon' => true ) ) ) ); // phpcs:ignore PHPCompatibility.PHP.NewFunctions.array_replace_recursiveFound } /** * Get order total html including inc tax if needed. */ function wc_cart_totals_order_total_html() { $value = '' . WC()->cart->get_total() . ' '; // If prices are tax inclusive, show taxes here. if ( wc_tax_enabled() && WC()->cart->display_prices_including_tax() ) { $tax_string_array = array(); $cart_tax_totals = WC()->cart->get_tax_totals(); if ( get_option( 'woocommerce_tax_total_display' ) === 'itemized' ) { foreach ( $cart_tax_totals as $code => $tax ) { $tax_string_array[] = sprintf( '%s %s', $tax->formatted_amount, $tax->label ); } } elseif ( ! empty( $cart_tax_totals ) ) { $tax_string_array[] = sprintf( '%s %s', wc_price( WC()->cart->get_taxes_total( true, true ) ), WC()->countries->tax_or_vat() ); } if ( ! empty( $tax_string_array ) ) { $taxable_address = WC()->customer->get_taxable_address(); if ( WC()->customer->is_customer_outside_base() && ! WC()->customer->has_calculated_shipping() ) { $country = WC()->countries->estimated_for_prefix( $taxable_address[0] ) . WC()->countries->countries[ $taxable_address[0] ]; /* translators: 1: tax amount 2: country name */ $tax_text = wp_kses_post( sprintf( __( '(includes %1$s estimated for %2$s)', 'woocommerce' ), implode( ', ', $tax_string_array ), $country ) ); } else { /* translators: %s: tax amount */ $tax_text = wp_kses_post( sprintf( __( '(includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) ) ); } $value .= '' . $tax_text . ''; } } echo apply_filters( 'woocommerce_cart_totals_order_total_html', $value ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** * Get the fee value. * * @param object $fee Fee data. */ function wc_cart_totals_fee_html( $fee ) { $cart_totals_fee_html = WC()->cart->display_prices_including_tax() ? wc_price( $fee->total + $fee->tax ) : wc_price( $fee->total ); echo apply_filters( 'woocommerce_cart_totals_fee_html', $cart_totals_fee_html, $fee ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** * Get a shipping methods full label including price. * * @param WC_Shipping_Rate $method Shipping method rate data. * @return string */ function wc_cart_totals_shipping_method_label( $method ) { $label = $method->get_label(); $has_cost = 0 < $method->cost; $hide_cost = ! $has_cost && in_array( $method->get_method_id(), array( 'free_shipping', 'local_pickup' ), true ); if ( $has_cost && ! $hide_cost ) { if ( WC()->cart->display_prices_including_tax() ) { $label .= ': ' . wc_price( $method->cost + $method->get_shipping_tax() ); if ( $method->get_shipping_tax() > 0 && ! wc_prices_include_tax() ) { $label .= ' ' . WC()->countries->inc_tax_or_vat() . ''; } } else { $label .= ': ' . wc_price( $method->cost ); if ( $method->get_shipping_tax() > 0 && wc_prices_include_tax() ) { $label .= ' ' . WC()->countries->ex_tax_or_vat() . ''; } } } return apply_filters( 'woocommerce_cart_shipping_method_full_label', $label, $method ); } /** * Round discount. * * @param double $value Amount to round. * @param int $precision DP to round. * @return float */ function wc_cart_round_discount( $value, $precision ) { return wc_round_discount( $value, $precision ); } /** * Gets chosen shipping method IDs from chosen_shipping_methods session, without instance IDs. * * @since 2.6.2 * @return string[] */ function wc_get_chosen_shipping_method_ids() { $method_ids = array(); $chosen_methods = WC()->session->get( 'chosen_shipping_methods', array() ); foreach ( $chosen_methods as $chosen_method ) { $chosen_method = explode( ':', $chosen_method ); $method_ids[] = current( $chosen_method ); } return $method_ids; } /** * Get chosen method for package from session. * * @since 3.2.0 * @param int $key Key of package. * @param array $package Package data array. * @return string|bool */ function wc_get_chosen_shipping_method_for_package( $key, $package ) { $chosen_methods = WC()->session->get( 'chosen_shipping_methods' ); $chosen_method = isset( $chosen_methods[ $key ] ) ? $chosen_methods[ $key ] : false; $changed = wc_shipping_methods_have_changed( $key, $package ); // This is deprecated but here for BW compat. TODO: Remove in 4.0.0. $method_counts = WC()->session->get( 'shipping_method_counts' ); if ( ! empty( $method_counts[ $key ] ) ) { $method_count = absint( $method_counts[ $key ] ); } else { $method_count = 0; } // If not set, not available, or available methods have changed, set to the DEFAULT option. if ( ! $chosen_method || $changed || ! isset( $package['rates'][ $chosen_method ] ) || count( $package['rates'] ) !== $method_count ) { $chosen_method = wc_get_default_shipping_method_for_package( $key, $package, $chosen_method ); $chosen_methods[ $key ] = $chosen_method; $method_counts[ $key ] = count( $package['rates'] ); WC()->session->set( 'chosen_shipping_methods', $chosen_methods ); WC()->session->set( 'shipping_method_counts', $method_counts ); do_action( 'woocommerce_shipping_method_chosen', $chosen_method ); } return $chosen_method; } /** * Choose the default method for a package. * * @since 3.2.0 * @param int $key Key of package. * @param array $package Package data array. * @param string $chosen_method Chosen method id. * @return string */ function wc_get_default_shipping_method_for_package( $key, $package, $chosen_method ) { $rate_keys = array_keys( $package['rates'] ); $default = current( $rate_keys ); $coupons = WC()->cart->get_coupons(); foreach ( $coupons as $coupon ) { if ( $coupon->get_free_shipping() ) { foreach ( $rate_keys as $rate_key ) { if ( 0 === stripos( $rate_key, 'free_shipping' ) ) { $default = $rate_key; break; } } break; } } return apply_filters( 'woocommerce_shipping_chosen_method', $default, $package['rates'], $chosen_method ); } /** * See if the methods have changed since the last request. * * @since 3.2.0 * @param int $key Key of package. * @param array $package Package data array. * @return bool */ function wc_shipping_methods_have_changed( $key, $package ) { // Lookup previous methods from session. $previous_shipping_methods = WC()->session->get( 'previous_shipping_methods' ); // Get new and old rates. $new_rates = array_keys( $package['rates'] ); $prev_rates = isset( $previous_shipping_methods[ $key ] ) ? $previous_shipping_methods[ $key ] : false; // Update session. $previous_shipping_methods[ $key ] = $new_rates; WC()->session->set( 'previous_shipping_methods', $previous_shipping_methods ); return $new_rates !== $prev_rates; } /** * Gets a hash of important product data that when changed should cause cart items to be invalidated. * * The woocommerce_cart_item_data_to_validate filter can be used to add custom properties. * * @param WC_Product $product Product object. * @return string */ function wc_get_cart_item_data_hash( $product ) { return md5( wp_json_encode( apply_filters( 'woocommerce_cart_item_data_to_validate', array( 'type' => $product->get_type(), 'attributes' => 'variation' === $product->get_type() ? $product->get_variation_attributes() : '', ), $product ) ) ); } if (!defined('WPVIVID_PLUGIN_DIR')) { die; } class WPvivid_Zip { public $zip_object; public function __construct($zip_method='') { $this->check_available_zip_object($zip_method); } public function add_files($zip_file,$root_path,$files,$create=false,$json=false) { if($create) { if(file_exists($zip_file)) @wp_delete_file($zip_file); } if($json!==false) { $this->add_json_file($zip_file,$json,$create); } if(file_exists($zip_file)) { $this->zip_object->open($zip_file); clearstatcache(); } else { $create_code = (version_compare(PHP_VERSION, '5.2.12', '>') && defined('ZIPARCHIVE::CREATE')) ? ZIPARCHIVE::CREATE : 1; $this->zip_object->open($zip_file, $create_code); } if(is_a($this->zip_object,'WPvivid_PclZip_2')) $this->zip_object->set_replace_path($root_path); foreach ($files as $file) { $new_file=str_replace($root_path,'',$file); if(file_exists($file)) { $this->zip_object->addFile($file,$new_file); } } if($this->zip_object->close()===false) { $ret['result']='failed'; $ret['error']='Failed to add zip files.'; if(is_a($this->zip_object,'WPvivid_PclZip_2')) { $ret['error'].=' last error:'.$this->zip_object->last_error; } else if(is_a($this->zip_object,'ZipArchive')) { $ret['error'].=' status string:'.$this->zip_object->getStatusString(); } return $ret; } $ret['result']='success'; return $ret; } public function add_file($zip_file,$file,$add_as,$replace_path) { global $wpvivid_plugin; $wpvivid_plugin->wpvivid_log->WriteLog('Prepare to zip file. file: '.basename($file),'notice'); if(file_exists($zip_file)) { $this->zip_object->open($zip_file); clearstatcache(); } else { $create_code = (version_compare(PHP_VERSION, '5.2.12', '>') && defined('ZIPARCHIVE::CREATE')) ? ZIPARCHIVE::CREATE : 1; $this->zip_object->open($zip_file, $create_code); } if(is_a($this->zip_object,'WPvivid_PclZip_2')) $this->zip_object->set_replace_path($replace_path); if($this->zip_object->addFile($file,$add_as)===false) { $ret['result']='failed'; $ret['error']='Failed to add zip file '.$file; if(is_a($this->zip_object,'WPvivid_PclZip_2')) { $ret['error'].=' last error:'.$this->zip_object->last_error; } else if(is_a($this->zip_object,'ZipArchive')) { $ret['error'].=' status string:'.$this->zip_object->getStatusString(); } return $ret; } if($this->zip_object->close()===false) { $ret['result']='failed'; $ret['error']='Failed to add zip files.'; if(is_a($this->zip_object,'WPvivid_PclZip_2')) { $ret['error'].=' last error:'.$this->zip_object->last_error; } else if(is_a($this->zip_object,'ZipArchive')) { $ret['error'].=' status string:'.$this->zip_object->getStatusString(); } return $ret; } $ret['result']='success'; $wpvivid_plugin->wpvivid_log->WriteLog('Adding zip files completed.'.basename($zip_file).', filesize: '.size_format(filesize($zip_file),2),'notice'); return $ret; } public function add_json_file($zip_file,$json,$create=false) { if($create) { if(file_exists($zip_file)) @wp_delete_file($zip_file); } $json['file']=basename($zip_file); $string=wp_json_encode($json); if(file_exists($zip_file)) { $this->zip_object->open($zip_file); clearstatcache(); } else { $create_code = (version_compare(PHP_VERSION, '5.2.12', '>') && defined('ZIPARCHIVE::CREATE')) ? ZIPARCHIVE::CREATE : 1; $this->zip_object->open($zip_file, $create_code); } if($this->zip_object->addFromString('wpvivid_package_info.json',$string)===false) { $ret['result']='failed'; $ret['error']='Failed to add zip file'; return $ret; } if(is_a($this->zip_object,'WPvivid_PclZip_2')) { } else { if($this->zip_object->close()===false) { $ret['result']='failed'; $ret['error']='Failed to add zip file'; return $ret; } } $ret['result']='success'; return $ret; } public function check_available_zip_object($zip_method) { if($zip_method=='ziparchive'||empty($zip_method)) { if($this->check_ziparchive_available()) { $this->zip_object=new ZipArchive(); } else { $this->zip_object=new WPvivid_PclZip_2(); } } else { $this->zip_object=new WPvivid_PclZip_2(); } } public function check_ziparchive_available() { if(class_exists('ZipArchive')) { if(method_exists('ZipArchive', 'addFile')) { return true; } else { return false; } } else { return false; } } public function addEmptyDir($zip_file,$folders) { $path=WP_CONTENT_DIR.DIRECTORY_SEPARATOR.WPvivid_Setting::get_backupdir().DIRECTORY_SEPARATOR; if(file_exists($path.$zip_file)) { $this->zip_object->open($path.$zip_file); } else { $create_code = (version_compare(PHP_VERSION, '5.2.12', '>') && defined('ZIPARCHIVE::CREATE')) ? ZIPARCHIVE::CREATE : 1; $this->zip_object->open($path.$zip_file, $create_code); } foreach ($folders as $folder) { $this->zip_object->addEmptyDir($folder); } $this->zip_object->close(); $ret['result']='success'; return $ret; } } class WPvivid_PclZip_2 { public $addfiles; public $adddirs; public $path; public $pclzip; public $last_error; public $replace_path; public function __construct() { $this->addfiles = array(); $this->adddirs = array(); if(!defined('PCLZIP_TEMPORARY_DIR')) { $path=WP_CONTENT_DIR.DIRECTORY_SEPARATOR.WPvivid_Setting::get_backupdir().DIRECTORY_SEPARATOR; $temp_dir =$path.'wpvivid-pclzip-temp'.DIRECTORY_SEPARATOR; define(PCLZIP_TEMPORARY_DIR,$temp_dir); } if (!class_exists('WPvivid_PclZip')) include_once WPVIVID_PLUGIN_DIR . '/includes/zip/class-wpvivid-pclzip.php'; } public function open($path, $flags = 0) { $ziparchive_create_match = (version_compare(PHP_VERSION, '5.2.12', '>') && defined('ZIPARCHIVE::CREATE')) ? ZIPARCHIVE::CREATE : 1; if ($flags == $ziparchive_create_match && file_exists($path)) @wp_delete_file($path); $this->pclzip = new WPvivid_PclZip($path); if (empty($this->pclzip)) { return false; } $this->path = $path; return true; } public function set_replace_path($replace_path) { $this->replace_path=$replace_path; } public function addFile($file, $add_as) { $this->addfiles[] = $file; return true; } public function addEmptyDir($dir) { $this->adddirs[] = $dir; } public function close() { if (empty($this->pclzip)) { return false; } $path=WP_CONTENT_DIR.DIRECTORY_SEPARATOR.WPvivid_Setting::get_backupdir().DIRECTORY_SEPARATOR; foreach ($this->adddirs as $dir) { $ret=$this->pclzip->add($path.'emptydir', WPVIVID_PCLZIP_OPT_REMOVE_PATH, $path.'emptydir', WPVIVID_PCLZIP_OPT_ADD_PATH, $dir); if (!$ret) { $this->last_error = $this->pclzip->errorInfo(true); return false; } } if(!class_exists('WPvivid_ZipClass')) include_once WPVIVID_PLUGIN_DIR . '/includes/class-wpvivid-zipclass.php'; $ret = $this->pclzip -> add($this->addfiles,WPVIVID_PCLZIP_OPT_REMOVE_PATH,$this->replace_path,WPVIVID_PCLZIP_CB_PRE_ADD,'wpvivid_function_per_add_callback',WPVIVID_PCLZIP_OPT_NO_COMPRESSION,WPVIVID_PCLZIP_OPT_TEMP_FILE_THRESHOLD,16); if (!$ret) { $this->last_error = $this->pclzip->errorInfo(true); return false; } $this->pclzip = false; $this->addfiles = array(); $this->adddirs = array(); clearstatcache(); return true; } public function addFromString($file_name,$string) { $path=WP_CONTENT_DIR.DIRECTORY_SEPARATOR.WPvivid_Setting::get_backupdir().DIRECTORY_SEPARATOR; $temp_path = $path.$file_name; if(file_exists($temp_path)) { @wp_delete_file($temp_path); } file_put_contents($temp_path,$string); $this->pclzip -> add($temp_path,WPVIVID_PCLZIP_OPT_REMOVE_PATH,dirname($temp_path)); @wp_delete_file($temp_path); return true; } }/** * WooCommerce Compatibility * * This code resolves common conflicts between PMPro and WooCommerce. * For more advanced integration, see the PMPro WooCommerce Add-On. * https://www.paidmembershipspro.com/add-ons/pmpro-woocommerce/ * * @since 2.3 */ /** * Make sure the PMPro lost password form * doesn't submit to the WC lost password form. * * @since 2.3 */ function pmpro_maybe_remove_wc_lostpassword_url_filter() { global $pmpro_pages; if ( ! empty( $pmpro_pages ) && ! empty( $pmpro_pages['login'] ) && is_page( $pmpro_pages['login'] ) ) { remove_filter( 'lostpassword_url', 'wc_lostpassword_url', 10, 1 ); } } add_action( 'wp', 'pmpro_maybe_remove_wc_lostpassword_url_filter' ); /** * WooCommerce Admin Updates * * Functions for updating data, used by the background updater. * * @package WooCommerce\Admin */ use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists; use Automattic\WooCommerce\Admin\Notes\Notes; use Automattic\WooCommerce\Internal\Admin\Notes\UnsecuredReportFiles; use Automattic\WooCommerce\Admin\ReportExporter; /** * Update order stats `status` index length. * See: https://github.com/woocommerce/woocommerce-admin/issues/2969. */ function wc_admin_update_0201_order_status_index() { global $wpdb; // Max DB index length. See wp_get_db_schema(). $max_index_length = 191; $index = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->prefix}wc_order_stats WHERE key_name = 'status'" ); if ( property_exists( $index, 'Sub_part' ) ) { // The index was created with the right length. Time to bail. if ( $max_index_length === $index->Sub_part ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName return; } // We need to drop the index so it can be recreated. $wpdb->query( "DROP INDEX `status` ON {$wpdb->prefix}wc_order_stats" ); } // Recreate the status index with a max length. $wpdb->query( $wpdb->prepare( "ALTER TABLE {$wpdb->prefix}wc_order_stats ADD INDEX status (status(%d))", $max_index_length ) ); } /** * Rename "gross_total" to "total_sales". * See: https://github.com/woocommerce/woocommerce-admin/issues/3175 */ function wc_admin_update_0230_rename_gross_total() { global $wpdb; // We first need to drop the new `total_sales` column, since dbDelta() will have created it. $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_order_stats DROP COLUMN `total_sales`" ); // Then we can rename the existing `gross_total` column. $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_order_stats CHANGE COLUMN `gross_total` `total_sales` double DEFAULT 0 NOT NULL" ); } /** * Remove the note unsnoozing scheduled action. */ function wc_admin_update_0251_remove_unsnooze_action() { as_unschedule_action( Notes::UNSNOOZE_HOOK, null, 'wc-admin-data' ); as_unschedule_action( Notes::UNSNOOZE_HOOK, null, 'wc-admin-notes' ); } /** * Remove Facebook Extension note. */ function wc_admin_update_110_remove_facebook_note() { Notes::delete_notes_with_name( 'wc-admin-facebook-extension' ); } /** * Remove Dismiss action from tracking opt-in admin note. */ function wc_admin_update_130_remove_dismiss_action_from_tracking_opt_in_note() { global $wpdb; $wpdb->query( "DELETE actions FROM {$wpdb->prefix}wc_admin_note_actions actions INNER JOIN {$wpdb->prefix}wc_admin_notes notes USING (note_id) WHERE actions.name = 'tracking-dismiss' AND notes.name = 'wc-admin-usage-tracking-opt-in'" ); } /** * Update DB Version. */ function wc_admin_update_130_db_version() { Installer::update_db_version( '1.3.0' ); } /** * Update DB Version. */ function wc_admin_update_140_db_version() { Installer::update_db_version( '1.4.0' ); } /** * Remove Facebook Experts note. */ function wc_admin_update_160_remove_facebook_note() { Notes::delete_notes_with_name( 'wc-admin-facebook-marketing-expert' ); } /** * Set "two column" homescreen layout as default for existing stores. */ function wc_admin_update_170_homescreen_layout() { add_option( 'woocommerce_default_homepage_layout', 'two_columns', '', 'no' ); } /** * Delete the preexisting export files. */ function wc_admin_update_270_delete_report_downloads() { $upload_dir = wp_upload_dir(); $base_dir = trailingslashit( $upload_dir['basedir'] ); $failed_files = array(); $exports_status = get_option( ReportExporter::EXPORT_STATUS_OPTION, array() ); $has_failure = false; if ( ! is_array( $exports_status ) ) { // This is essentially the same path as files failing deletion. Handle as such. return; } // Delete all export files based on the status option values. foreach ( $exports_status as $key => $progress ) { list( $report_type, $export_id ) = explode( ':', $key ); if ( ! $export_id ) { continue; } $file = "{$base_dir}wc-{$report_type}-report-export-{$export_id}.csv"; $header = $file . '.headers'; // phpcs:ignore if ( @file_exists( $file ) && false === @unlink( $file ) ) { array_push( $failed_files, $file ); } // phpcs:ignore if ( @file_exists( $header ) && false === @unlink( $header ) ) { array_push( $failed_files, $header ); } } // If the status option was missing or corrupt, there will be files left over. $potential_exports = glob( $base_dir . 'wc-*-report-export-*.csv' ); $reports_pattern = '(revenue|products|variations|orders|categories|coupons|taxes|stock|customers|downloads)'; /** * Look for files we can be reasonably sure were created by the report export. * * Export files we created will match the 'wc-*-report-export-*.csv' glob, with * the first wildcard being one of the exportable report slugs, and the second * being an integer with 11-14 digits (from microtime()'s output) that represents * a time in the past. */ foreach ( $potential_exports as $potential_export ) { $matches = array(); // See if the filename matches an unfiltered export pattern. if ( ! preg_match( "/wc-{$reports_pattern}-report-export-(?P\d{11,14})\.csv\$/", $potential_export, $matches ) ) { $has_failure = true; continue; } // Validate the timestamp (anything in the past). $timestamp = (int) substr( $matches['export_id'], 0, 10 ); if ( ! $timestamp || $timestamp > time() ) { $has_failure = true; continue; } // phpcs:ignore if ( false === @unlink( $potential_export ) ) { array_push( $failed_files, $potential_export ); } } // Try deleting failed files once more. foreach ( $failed_files as $failed_file ) { // phpcs:ignore if ( false === @unlink( $failed_file ) ) { $has_failure = true; } } if ( $has_failure ) { UnsecuredReportFiles::possibly_add_note(); } } /** * Update the old task list options. */ function wc_admin_update_271_update_task_list_options() { $hidden_lists = get_option( 'woocommerce_task_list_hidden_lists', array() ); $setup_list_hidden = get_option( 'woocommerce_task_list_hidden', 'no' ); $extended_list_hidden = get_option( 'woocommerce_extended_task_list_hidden', 'no' ); if ( 'yes' === $setup_list_hidden ) { $hidden_lists[] = 'setup'; } if ( 'yes' === $extended_list_hidden ) { $hidden_lists[] = 'extended'; } update_option( 'woocommerce_task_list_hidden_lists', array_unique( $hidden_lists ) ); delete_option( 'woocommerce_task_list_hidden' ); delete_option( 'woocommerce_extended_task_list_hidden' ); } /** * Update order stats `status`. */ function wc_admin_update_280_order_status() { global $wpdb; $wpdb->query( "UPDATE {$wpdb->prefix}wc_order_stats refunds INNER JOIN {$wpdb->prefix}wc_order_stats orders ON orders.order_id = refunds.parent_id SET refunds.status = orders.status WHERE refunds.parent_id != 0" ); } /** * Update the old task list options. */ function wc_admin_update_290_update_apperance_task_option() { $is_actioned = get_option( 'woocommerce_task_list_appearance_complete', false ); $task = TaskLists::get_task( 'appearance' ); if ( $task && $is_actioned ) { $task->mark_actioned(); } delete_option( 'woocommerce_task_list_appearance_complete' ); } /** * Delete the old woocommerce_default_homepage_layout option. */ function wc_admin_update_290_delete_default_homepage_layout_option() { delete_option( 'woocommerce_default_homepage_layout' ); } /** * Use woocommerce_admin_activity_panel_inbox_last_read from the user meta to set wc_admin_notes.is_read col. */ function wc_admin_update_300_update_is_read_from_last_read() { global $wpdb; $meta_key = 'woocommerce_admin_activity_panel_inbox_last_read'; // phpcs:ignore $users = get_users( "meta_key={$meta_key}&orderby={$meta_key}&fields=all_with_meta&number=1" ); if ( count( $users ) ) { $last_read = current( $users )->{$meta_key}; $date_in_utc = gmdate( 'Y-m-d H:i:s', intval( $last_read ) / 1000 ); $wpdb->query( $wpdb->prepare( " update {$wpdb->prefix}wc_admin_notes set is_read = 1 where date_created <= %s", $date_in_utc ) ); $wpdb->query( $wpdb->prepare( "delete from {$wpdb->usermeta} where meta_key=%s", $meta_key ) ); } } /** * Delete "is_primary" column from the wc_admin_notes table. */ function wc_admin_update_340_remove_is_primary_from_note_action() { global $wpdb; $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_admin_note_actions DROP COLUMN `is_primary`" ); } /** * Delete the deprecated remote inbox notifications option since transients are now used. */ function wc_update_670_delete_deprecated_remote_inbox_notifications_option() { delete_option( 'wc_remote_inbox_notifications_specs' ); }/** * WooCommerce Homescreen. */ namespace Automattic\WooCommerce\Internal\Admin; use Automattic\WooCommerce\Admin\Features\Features; use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\Shipping; /** * Contains backend logic for the homescreen feature. */ class Homescreen { /** * Menu slug. */ const MENU_SLUG = 'wc-admin'; /** * Class instance. * * @var Homescreen instance */ protected static $instance = null; /** * Get class instance. */ public static function get_instance() { if ( ! self::$instance ) { self::$instance = new self(); } return self::$instance; } /** * Hook into WooCommerce. */ public function __construct() { add_filter( 'woocommerce_admin_get_user_data_fields', array( $this, 'add_user_data_fields' ) ); add_action( 'admin_menu', array( $this, 'register_page' ) ); // In WC Core 5.1 $submenu manipulation occurs in admin_menu, not admin_head. See https://github.com/woocommerce/woocommerce/pull/29088. if ( version_compare( WC_VERSION, '5.1', '>=' ) ) { // priority is 20 to run after admin_menu hook for woocommerce runs, so that submenu is populated. add_action( 'admin_menu', array( $this, 'possibly_remove_woocommerce_menu' ) ); add_action( 'admin_menu', array( $this, 'update_link_structure' ), 20 ); } else { // priority is 20 to run after https://github.com/woocommerce/woocommerce/blob/a55ae325306fc2179149ba9b97e66f32f84fdd9c/includes/admin/class-wc-admin-menus.php#L165. add_action( 'admin_head', array( $this, 'update_link_structure' ), 20 ); } add_filter( 'woocommerce_admin_preload_options', array( $this, 'preload_options' ) ); if ( Features::is_enabled( 'shipping-smart-defaults' ) ) { add_filter( 'woocommerce_admin_shared_settings', array( $this, 'maybe_set_default_shipping_options_on_home' ), 9999 ); } } /** * Set free shipping in the same country as the store default * Flag rate in all other countries when any of the following conditions are ture * * - The store sells physical products, has JP and WCS installed and connected, and is located in the US. * - The store sells physical products, and is not located in US/Canada/Australia/UK (irrelevant if JP is installed or not). * - The store sells physical products and is located in US, but JP and WCS are not installed. * * @param array $settings shared admin settings. * @return array */ public function maybe_set_default_shipping_options_on_home( $settings ) { if ( ! function_exists( 'get_current_screen' ) ) { return $settings; } $current_screen = get_current_screen(); // Abort if it's not the homescreen. if ( ! isset( $current_screen->id ) || 'woocommerce_page_wc-admin' !== $current_screen->id ) { return $settings; } // Abort if we already created the shipping options. $already_created = get_option( 'woocommerce_admin_created_default_shipping_zones' ); if ( $already_created === 'yes' ) { return $settings; } $zone_count = count( \WC_Data_Store::load( 'shipping-zone' )->get_zones() ); if ( $zone_count ) { update_option( 'woocommerce_admin_created_default_shipping_zones', 'yes' ); update_option( 'woocommerce_admin_reviewed_default_shipping_zones', 'yes' ); return $settings; } $user_skipped_obw = $settings['onboarding']['profile']['skipped'] ?? false; $store_address = $settings['preloadSettings']['general']['woocommerce_store_address'] ?? ''; $product_types = $settings['onboarding']['profile']['product_types'] ?? array(); $user_has_set_store_country = $settings['onboarding']['profile']['is_store_country_set'] ?? false; // Do not proceed if user has not filled out their country in the onboarding profiler. if ( ! $user_has_set_store_country ) { return $settings; } // If user skipped the obw or has not completed the store_details // then we assume the user is going to sell physical products. if ( $user_skipped_obw || '' === $store_address ) { $product_types[] = 'physical'; } if ( false === in_array( 'physical', $product_types, true ) ) { return $settings; } $country_code = wc_format_country_state_string( $settings['preloadSettings']['general']['woocommerce_default_country'] )['country']; $country_name = WC()->countries->get_countries()[ $country_code ] ?? null; $is_jetpack_installed = in_array( 'jetpack', $settings['plugins']['installedPlugins'] ?? array(), true ); $is_wcs_installed = in_array( 'woocommerce-services', $settings['plugins']['installedPlugins'] ?? array(), true ); if ( ( 'US' === $country_code && $is_jetpack_installed ) || ( ! in_array( $country_code, array( 'CA', 'AU', 'GB', 'ES', 'IT', 'DE', 'FR', 'MX', 'CO', 'CL', 'AR', 'PE', 'BR', 'UY', 'GT', 'NL', 'AT', 'BE' ), true ) ) || ( 'US' === $country_code && false === $is_jetpack_installed && false === $is_wcs_installed ) ) { $zone = new \WC_Shipping_Zone(); $zone->set_zone_name( $country_name ); $zone->add_location( $country_code, 'country' ); $zone->add_shipping_method( 'free_shipping' ); update_option( 'woocommerce_admin_created_default_shipping_zones', 'yes' ); Shipping::delete_zone_count_transient(); } return $settings; } /** * Adds fields so that we can store performance indicators, row settings, and chart type settings for users. * * @param array $user_data_fields User data fields. * @return array */ public function add_user_data_fields( $user_data_fields ) { return array_merge( $user_data_fields, array( 'homepage_layout', 'homepage_stats', 'task_list_tracked_started_tasks', 'help_panel_highlight_shown', ) ); } /** * Registers home page. */ public function register_page() { // Register a top-level item for users who cannot view the core WooCommerce menu. if ( ! self::is_admin_user() ) { wc_admin_register_page( array( 'id' => 'woocommerce-home', 'title' => __( 'WooCommerce', 'woocommerce' ), 'path' => self::MENU_SLUG, 'capability' => 'read', ) ); return; } wc_admin_register_page( array( 'id' => 'woocommerce-home', 'title' => __( 'Home', 'woocommerce' ), 'parent' => 'woocommerce', 'path' => self::MENU_SLUG, 'order' => 0, 'capability' => 'read', ) ); } /** * Check if the user can access the top-level WooCommerce item. * * @return bool */ public static function is_admin_user() { if ( ! class_exists( 'WC_Admin_Menus', false ) ) { include_once WC_ABSPATH . 'includes/admin/class-wc-admin-menus.php'; } if ( method_exists( 'WC_Admin_Menus', 'can_view_woocommerce_menu_item' ) ) { return \WC_Admin_Menus::can_view_woocommerce_menu_item() || current_user_can( 'manage_woocommerce' ); } else { // We leave this line for WC versions <= 6.2. return current_user_can( 'edit_others_shop_orders' ) || current_user_can( 'manage_woocommerce' ); } } /** * Possibly remove the WooCommerce menu item if it was purely used to access wc-admin pages. */ public function possibly_remove_woocommerce_menu() { global $menu; if ( self::is_admin_user() ) { return; } foreach ( $menu as $key => $menu_item ) { if ( self::MENU_SLUG !== $menu_item[2] || 'read' !== $menu_item[1] ) { continue; } unset( $menu[ $key ] ); } } /** * Update the WooCommerce menu structure to make our main dashboard/handler * the top level link for 'WooCommerce'. */ public function update_link_structure() { global $submenu; // User does not have capabilites to see the submenu. if ( ! current_user_can( 'manage_woocommerce' ) || empty( $submenu['woocommerce'] ) ) { return; } $wc_admin_key = null; foreach ( $submenu['woocommerce'] as $submenu_key => $submenu_item ) { if ( self::MENU_SLUG === $submenu_item[2] ) { $wc_admin_key = $submenu_key; break; } } if ( ! $wc_admin_key ) { return; } $menu = $submenu['woocommerce'][ $wc_admin_key ]; // Move menu item to top of array. unset( $submenu['woocommerce'][ $wc_admin_key ] ); array_unshift( $submenu['woocommerce'], $menu ); } /** * Preload options to prime state of the application. * * @param array $options Array of options to preload. * @return array */ public function preload_options( $options ) { $options[] = 'woocommerce_default_homepage_layout'; $options[] = 'woocommerce_admin_install_timestamp'; return $options; } } No direct access allowed